foundr-companion 0.1.1 → 0.1.3

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.
@@ -2,4 +2,24 @@ export function authFilePath(): string;
2
2
  export function loadBridgeAuth(file?: string): Promise<any>;
3
3
  export function saveBridgeAuth(auth: any, file?: string): Promise<void>;
4
4
  export function deleteBridgeAuth(file?: string): Promise<void>;
5
+ /**
6
+ * Read the persisted pairing WITHOUT any network call. `paired` mirrors the
7
+ * daemon's own readiness check (a stored agent id — see startCompanionDaemon).
8
+ * Never throws: a missing or corrupt credentials file resolves to
9
+ * `{ paired: false }`.
10
+ */
11
+ export function readLocalPairing(file?: string): Promise<{
12
+ paired: boolean;
13
+ hasToken: boolean;
14
+ agent?: undefined;
15
+ mcpUrl?: undefined;
16
+ } | {
17
+ paired: boolean;
18
+ agent: {
19
+ id: any;
20
+ name: any;
21
+ };
22
+ mcpUrl: any;
23
+ hasToken: boolean;
24
+ }>;
5
25
  //# sourceMappingURL=bridge-auth.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bridge-auth.d.mts","sourceRoot":"","sources":["../../src/bridge/bridge-auth.mjs"],"names":[],"mappings":"AAIA,uCAEC;AAED,4DAGC;AAED,wEAMC;AAED,+DAEC"}
1
+ {"version":3,"file":"bridge-auth.d.mts","sourceRoot":"","sources":["../../src/bridge/bridge-auth.mjs"],"names":[],"mappings":"AAIA,uCAEC;AAED,4DAGC;AAED,wEAMC;AAED,+DAEC;AAED;;;;;GAKG;AACH;;;;;;;;;;;;;GAUC"}
@@ -22,3 +22,21 @@ export async function saveBridgeAuth(auth, file = authFilePath()) {
22
22
  export async function deleteBridgeAuth(file = authFilePath()) {
23
23
  await fs.rm(file, { force: true })
24
24
  }
25
+
26
+ /**
27
+ * Read the persisted pairing WITHOUT any network call. `paired` mirrors the
28
+ * daemon's own readiness check (a stored agent id — see startCompanionDaemon).
29
+ * Never throws: a missing or corrupt credentials file resolves to
30
+ * `{ paired: false }`.
31
+ */
32
+ export async function readLocalPairing(file = authFilePath()) {
33
+ const auth = await loadBridgeAuth(file).catch(() => null)
34
+ const hasToken = Boolean(auth?.tokens?.access_token)
35
+ if (!auth?.agent?.id) return { paired: false, hasToken }
36
+ return {
37
+ paired: true,
38
+ agent: { id: auth.agent.id, name: auth.agent.name ?? auth.agent.id },
39
+ mcpUrl: auth.mcpUrl ?? undefined,
40
+ hasToken,
41
+ }
42
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"bridge-auth.mjs","sourceRoot":"","sources":["../../src/bridge/bridge-auth.mjs"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACjC,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,eAAe,EAAE,kBAAkB,CAAC,CAAA;AACrE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAI,GAAG,YAAY,EAAE;IACxD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAC3C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;AACxB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,EAAE;IAC9D,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9B,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IACrD,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IAC1B,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IAC/E,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;AAC7B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAI,GAAG,YAAY,EAAE;IAC1D,MAAM,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;AACpC,CAAC"}
1
+ {"version":3,"file":"bridge-auth.mjs","sourceRoot":"","sources":["../../src/bridge/bridge-auth.mjs"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACjC,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,eAAe,EAAE,kBAAkB,CAAC,CAAA;AACrE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAI,GAAG,YAAY,EAAE;IACxD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAC3C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;AACxB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,EAAE;IAC9D,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9B,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IACrD,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IAC1B,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IAC/E,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;AAC7B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAI,GAAG,YAAY,EAAE;IAC1D,MAAM,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;AACpC,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAI,GAAG,YAAY,EAAE;;IAC1D,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;IACzD,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,MAAM,0CAAE,YAAY,CAAC,CAAA;IACpD,IAAI,CAAC,CAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,KAAK,0CAAE,EAAE,CAAA;QAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAA;IACxD,OAAO;QACL,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,MAAA,IAAI,CAAC,KAAK,CAAC,IAAI,mCAAI,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE;QACpE,MAAM,EAAE,MAAA,IAAI,CAAC,MAAM,mCAAI,SAAS;QAChC,QAAQ;KACT,CAAA;AACH,CAAC"}
@@ -5,7 +5,7 @@
5
5
  import fs from 'node:fs/promises'
6
6
  import os from 'node:os'
7
7
  import path from 'node:path'
8
- import { loadBridgeAuth, saveBridgeAuth, deleteBridgeAuth } from './bridge-auth.mjs'
8
+ import { loadBridgeAuth, saveBridgeAuth, deleteBridgeAuth, readLocalPairing } from './bridge-auth.mjs'
9
9
  import { createMcpClient, createOAuthCallbackWaiter, withVercelProtectionBypass } from './mcp-client.mjs'
10
10
  import { FileBackedOAuthProvider } from './oauth-provider.mjs'
11
11
  import { logoutFoundrBridge } from './logout.mjs'
@@ -95,6 +95,135 @@ export async function logoutCompanion() {
95
95
  await logoutFoundrBridge({ loadAuth: loadBridgeAuth, deleteAuth: deleteBridgeAuth })
96
96
  }
97
97
 
98
+ // Re-export the no-network local pairing read so the CLI gets it (and its type
99
+ // via daemon.d.mts) from the same bridge surface as the rest of the daemon.
100
+ export { readLocalPairing }
101
+
102
+ /** Classify why a live verification failed, for an actionable status message. */
103
+ export function classifyLiveError(err) {
104
+ const code = err?.code
105
+ const status = err?.status ?? err?.statusCode
106
+ const name = err?.name
107
+ const m = String(err?.message ?? err ?? '').toLowerCase()
108
+ if (
109
+ name === 'UnauthorizedError' ||
110
+ status === 401 || status === 403 ||
111
+ code === 'AUTH_FAILED' ||
112
+ /unauthor|reauthor|invalid_token|invalid_grant|forbidden|access denied/.test(m)
113
+ ) {
114
+ return 'auth'
115
+ }
116
+ if (
117
+ name === 'AbortError' ||
118
+ code === 'ENOTFOUND' || code === 'ECONNREFUSED' || code === 'ETIMEDOUT' || code === 'EAI_AGAIN' ||
119
+ /timed out|timeout|fetch failed|network|getaddrinfo|enotfound|econnrefused|socket hang/.test(m)
120
+ ) {
121
+ return 'network'
122
+ }
123
+ return 'other'
124
+ }
125
+
126
+ /**
127
+ * Confirm the stored pairing is live by calling the heartbeat tool with the
128
+ * persisted token (the MCP SDK refreshes it transparently). NON-interactive: a
129
+ * dead token surfaces as `live:false` instead of opening a browser, and a hung
130
+ * server is bounded by `timeoutMs`. Always resolves (never rejects) so callers
131
+ * can report a definite state.
132
+ */
133
+ export async function verifyCompanionPairing({ timeoutMs = 15000 } = {}) {
134
+ const local = await readLocalPairing()
135
+ if (!local.paired) return { ...local, live: false }
136
+
137
+ const auth = await loadBridgeAuth().catch(() => null)
138
+ if (!auth?.agent?.id) {
139
+ return { ...local, live: false, liveError: 'other', reason: 'credentials unreadable' }
140
+ }
141
+ const mcpUrl = auth.mcpUrl || DEFAULT_MCP_URL
142
+ const agentName = auth.agentName || DEFAULT_AGENT_NAME
143
+
144
+ const provider = new FileBackedOAuthProvider({
145
+ mcpUrl,
146
+ agentName,
147
+ auth,
148
+ onChange: async (nextAuth) => {
149
+ await saveBridgeAuth({
150
+ ...nextAuth,
151
+ mcpUrl,
152
+ agentName,
153
+ agent: auth.agent,
154
+ updatedAt: new Date().toISOString(),
155
+ })
156
+ },
157
+ onRedirect: () => {}, // a verification must never prompt the user
158
+ })
159
+
160
+ // A callback whose `code` rejects immediately: if the SDK cannot satisfy auth
161
+ // via a refresh it raises UnauthorizedError and createMcpClient awaits this
162
+ // `code` — rejecting turns that into a fast error instead of a hang on a
163
+ // browser round-trip that will never happen during a status check.
164
+ const nonInteractiveCallback = () => {
165
+ const code = Promise.reject(new Error('reauthorization required'))
166
+ code.catch(() => {})
167
+ return { ready: Promise.resolve(0), code, get port() { return 0 }, close() {} }
168
+ }
169
+
170
+ let timedOut = false
171
+ let timer
172
+ let mcp = null
173
+
174
+ // Build the client + heartbeat as a tracked promise (not inlined into the
175
+ // race). Promise.race never settles the LOSING branch, so if the timeout wins
176
+ // and `work` later rejects (a slow server answering after the deadline) it
177
+ // would become an unhandled rejection that crashes the CLI — and a client that
178
+ // connects after the deadline would leak. The always-attached settlement
179
+ // handler below neutralizes both: it swallows a late rejection and closes a
180
+ // late-built client. (A token endpoint that hangs forever can't be actively
181
+ // aborted — the SDK's refresh fetch takes no signal — but the race still
182
+ // returns within timeoutMs and the short-lived CLI process reaps the socket.)
183
+ const work = (async () => {
184
+ mcp = await createMcpClient({
185
+ mcpUrl,
186
+ authProvider: provider,
187
+ oauthCallbackFactory: nonInteractiveCallback,
188
+ })
189
+ return mcp.callTool('heartbeat_private_chat_listener', {
190
+ client_name: CLIENT_NAME,
191
+ client_version: CLIENT_VERSION,
192
+ status: 'stopped',
193
+ })
194
+ })()
195
+ work.then(
196
+ () => { if (timedOut) mcp?.close?.().catch(() => {}) },
197
+ () => { if (timedOut) mcp?.close?.().catch(() => {}) },
198
+ )
199
+
200
+ const timeout = new Promise((_resolve, reject) => {
201
+ timer = setTimeout(() => {
202
+ timedOut = true
203
+ reject(Object.assign(new Error('verification timed out'), { name: 'AbortError' }))
204
+ }, timeoutMs)
205
+ })
206
+
207
+ try {
208
+ const heartbeat = await Promise.race([work, timeout])
209
+ const agent = heartbeat?.agent?.id
210
+ ? { id: heartbeat.agent.id, name: heartbeat.agent.name ?? heartbeat.agent.id }
211
+ : local.agent
212
+ return { paired: true, live: true, agent, mcpUrl }
213
+ } catch (err) {
214
+ return {
215
+ ...local,
216
+ live: false,
217
+ liveError: classifyLiveError(err),
218
+ reason: err instanceof Error ? err.message : String(err),
219
+ }
220
+ } finally {
221
+ clearTimeout(timer)
222
+ // The timeout path closes the (possibly late) client via work.then above.
223
+ if (!timedOut) await mcp?.close?.().catch(() => {})
224
+ }
225
+ }
226
+
98
227
  function isProcessAlive(pid) {
99
228
  if (!Number.isInteger(pid) || pid <= 0) return false
100
229
  try {
package/dist/cli.js CHANGED
@@ -1,13 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs/promises';
3
+ import path from 'node:path';
3
4
  import { spawn } from 'node:child_process';
4
5
  import { createRequire } from 'node:module';
5
6
  import { fileURLToPath } from 'node:url';
6
- import { parseCli, readOption } from './cli-parse.js';
7
+ import { parseCli, readOption, hasFlag } from './cli-parse.js';
7
8
  import { companionPaths, LAUNCH_AGENT_LABEL } from './paths.js';
8
9
  import { installLaunchAgent, isLaunchAgentLoaded, renderLaunchAgentPlist, restartLaunchAgent, uninstallLaunchAgent, } from './launchd.js';
9
10
  import { codexPreflight } from './codex-preflight.js';
10
- import { DEFAULT_MCP_URL, loginCompanion, logoutCompanion, resolveMcpUrl, startCompanionDaemon, } from './bridge/daemon.mjs';
11
+ import { DEFAULT_MCP_URL, loginCompanion, logoutCompanion, readLocalPairing, resolveMcpUrl, startCompanionDaemon, verifyCompanionPairing, } from './bridge/daemon.mjs';
12
+ import { decideLogin, installPairingLine, pairingStatusLine } from './pairing-status.js';
11
13
  const require = createRequire(import.meta.url);
12
14
  const VERSION = require('../package.json').version;
13
15
  // dist/cli.js at runtime — the absolute path launchd should exec.
@@ -21,7 +23,8 @@ function usage() {
21
23
  'Usage: foundr <command>',
22
24
  '',
23
25
  'Setup:',
24
- ' login Pair this machine with Founder World (opens a browser)',
26
+ ' login Pair this machine with Founder World (opens a browser).',
27
+ ' Detects an existing pairing; use --force to re-pair.',
25
28
  ' codex Check your Codex CLI login (Sign in with ChatGPT)',
26
29
  ' install Install + start the background service (launchd)',
27
30
  '',
@@ -41,6 +44,8 @@ function usage() {
41
44
  ' --url <origin> Founder World origin (default https://www.foundr.world).',
42
45
  ' Also honored via FOUNDR_URL. Use a *.lab.foundr.world',
43
46
  ' origin to target a lab deploy.',
47
+ ' --force With `login`: re-pair even if already paired.',
48
+ ' --local With `status`: skip the online check (on-disk state only).',
44
49
  ].join('\n');
45
50
  }
46
51
  function run(cmd, args) {
@@ -52,7 +57,26 @@ function run(cmd, args) {
52
57
  }
53
58
  async function cmdLogin(args) {
54
59
  var _a, _b;
55
- const mcpUrl = resolveMcpUrl((_b = (_a = readOption(args, '--url')) !== null && _a !== void 0 ? _a : process.env.FOUNDR_URL) !== null && _b !== void 0 ? _b : DEFAULT_MCP_URL);
60
+ const force = hasFlag(args, '--force') || hasFlag(args, '--relogin');
61
+ // Detect an existing pairing before re-running OAuth.
62
+ const local = await readLocalPairing();
63
+ // A bare `login` re-verifies the EXISTING pairing's origin (fall back to it),
64
+ // so a lab-paired machine isn't silently re-pointed at the prod default. Only
65
+ // an explicit --url / FOUNDR_URL counts as a deliberate origin change.
66
+ const explicitUrl = (_a = readOption(args, '--url')) !== null && _a !== void 0 ? _a : process.env.FOUNDR_URL;
67
+ const mcpUrl = resolveMcpUrl((_b = explicitUrl !== null && explicitUrl !== void 0 ? explicitUrl : local.mcpUrl) !== null && _b !== void 0 ? _b : DEFAULT_MCP_URL);
68
+ // The live check only short-circuits when targeting the SAME origin we're
69
+ // paired to. If --url points elsewhere (or there's no pairing, or --force),
70
+ // skip the round-trip and let decideLogin route to pairing — otherwise a live
71
+ // heartbeat against the OLD origin would falsely block a deliberate re-point.
72
+ const originChanged = Boolean(explicitUrl && local.paired && local.mcpUrl && resolveMcpUrl(local.mcpUrl) !== mcpUrl);
73
+ const current = force || originChanged || !local.paired
74
+ ? Object.assign(Object.assign({}, local), { live: false }) : await verifyCompanionPairing();
75
+ const decision = decideLogin(current, { force, originChanged });
76
+ for (const line of decision.lines)
77
+ console.log(line);
78
+ if (decision.action === 'already-paired')
79
+ return 0;
56
80
  const { agent } = await loginCompanion({ mcpUrl });
57
81
  console.log(`Paired as ${agent.name} (${agent.id}).`);
58
82
  console.log('Next: run `foundr install` to start the background service.');
@@ -66,14 +90,26 @@ async function cmdCodex() {
66
90
  console.log(' • ' + g);
67
91
  return pf.ok ? 0 : 1;
68
92
  }
69
- async function writePlistAndLoad() {
93
+ async function writePlistAndLoad(urlOverride) {
70
94
  const paths = companionPaths();
71
95
  await fs.mkdir(paths.logsDir, { recursive: true });
72
96
  await fs.mkdir(paths.launchAgentsDir, { recursive: true });
73
97
  const env = {};
74
- const url = process.env.FOUNDR_URL;
98
+ // The listener prefers the origin stored at pairing time (auth.mcpUrl); this
99
+ // plist env is the fallback. Honor an explicit --url so `install --url …`
100
+ // isn't silently ignored, as the global help implies it's supported.
101
+ const url = urlOverride !== null && urlOverride !== void 0 ? urlOverride : process.env.FOUNDR_URL;
75
102
  if (url)
76
103
  env.FOUNDR_URL = url;
104
+ // launchd starts jobs with a minimal PATH (/usr/bin:/bin:/usr/sbin:/sbin) that
105
+ // omits where `codex` (and node) actually live — Homebrew, nvm, npm-global.
106
+ // `foundr install` runs in the user's shell, whose PATH DID resolve `codex`, so
107
+ // capture it. Without this the daemon's Codex preflight can't find the binary,
108
+ // `foundr run` exits "codex not ready", and the listener never starts — the
109
+ // agent shows offline in-game even though `foundr status` (shell) says ready.
110
+ env.PATH = [path.dirname(process.execPath), process.env.PATH].filter(Boolean).join(':');
111
+ if (process.env.CODEX_HOME)
112
+ env.CODEX_HOME = process.env.CODEX_HOME;
77
113
  const plist = renderLaunchAgentPlist({
78
114
  label: LAUNCH_AGENT_LABEL,
79
115
  nodePath: process.execPath,
@@ -89,18 +125,20 @@ async function writePlistAndLoad() {
89
125
  await installLaunchAgent({ plistPath: paths.launchAgentPlist, label: LAUNCH_AGENT_LABEL });
90
126
  }
91
127
  }
92
- async function cmdInstall() {
93
- await writePlistAndLoad();
128
+ async function cmdInstall(args) {
129
+ await writePlistAndLoad(readOption(args, '--url'));
94
130
  console.log('Installed and started the Foundr companion (launchd).');
95
131
  const pf = await codexPreflight();
96
132
  if (!pf.ok)
97
133
  for (const g of pf.guidance)
98
134
  console.log(' • ' + g);
99
- console.log('If not paired yet: run `foundr login`.');
135
+ // Report the actual pairing state instead of a blanket "if not paired" hint.
136
+ // Local read only — keep install fast and offline-safe.
137
+ console.log(installPairingLine(await readLocalPairing()));
100
138
  return 0;
101
139
  }
102
- async function cmdStart() {
103
- await writePlistAndLoad();
140
+ async function cmdStart(args) {
141
+ await writePlistAndLoad(readOption(args, '--url'));
104
142
  console.log('Started.');
105
143
  return 0;
106
144
  }
@@ -127,23 +165,18 @@ async function cmdUninstall() {
127
165
  console.log('Credentials remain in ~/.foundr-world — run `foundr logout` to clear them.');
128
166
  return 0;
129
167
  }
130
- async function cmdStatus() {
131
- var _a, _b;
132
- const paths = companionPaths();
168
+ async function cmdStatus(args) {
169
+ var _a;
133
170
  const loaded = await isLaunchAgentLoaded({ label: LAUNCH_AGENT_LABEL });
134
- let paired = null;
135
- try {
136
- const a = JSON.parse(await fs.readFile(paths.authFile, 'utf8'));
137
- paired = (_a = a.agent) !== null && _a !== void 0 ? _a : null;
138
- }
139
- catch (_c) {
140
- paired = null;
141
- }
171
+ // Default to a live check (heartbeat) so `paired:` reflects reality; --local
172
+ // / --no-verify skips the network round-trip and reports the on-disk state.
173
+ const localOnly = hasFlag(args, '--local') || hasFlag(args, '--no-verify');
174
+ const pairing = localOnly ? await readLocalPairing() : await verifyCompanionPairing();
142
175
  const pf = await codexPreflight();
143
176
  console.log('Foundr companion');
144
- console.log(` paired: ${paired ? `${paired.name} (${paired.id})` : 'no — run: foundr login'}`);
177
+ console.log(` paired: ${pairingStatusLine(pairing)}`);
145
178
  console.log(` service: ${loaded ? 'running (launchd)' : 'not installed — run: foundr install'}`);
146
- console.log(` codex: ${pf.ok ? `ready (${(_b = pf.authMode) !== null && _b !== void 0 ? _b : 'unknown'})` : 'not ready'}`);
179
+ console.log(` codex: ${pf.ok ? `ready (${(_a = pf.authMode) !== null && _a !== void 0 ? _a : 'unknown'})` : 'not ready'}`);
147
180
  for (const g of pf.guidance)
148
181
  console.log(' • ' + g);
149
182
  return 0;
@@ -202,17 +235,17 @@ async function main() {
202
235
  case 'codex':
203
236
  return cmdCodex();
204
237
  case 'install':
205
- return cmdInstall();
238
+ return cmdInstall(parsed.args);
206
239
  case 'uninstall':
207
240
  return cmdUninstall();
208
241
  case 'start':
209
- return cmdStart();
242
+ return cmdStart(parsed.args);
210
243
  case 'stop':
211
244
  return cmdStop();
212
245
  case 'restart':
213
246
  return cmdRestart();
214
247
  case 'status':
215
- return cmdStatus();
248
+ return cmdStatus(parsed.args);
216
249
  case 'update':
217
250
  return cmdUpdate();
218
251
  case 'run':
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Pure rendering + decision logic for the companion's pairing state.
3
+ *
4
+ * Kept free of any I/O so the `foundr login` / `install` / `status` UX is fully
5
+ * testable. The bridge daemon supplies the data (`readLocalPairing` for the
6
+ * no-network check, `verifyCompanionPairing` for the live heartbeat check); this
7
+ * module turns that data into the exact lines the CLI prints and the decision of
8
+ * whether `login` should short-circuit.
9
+ */
10
+ export interface PairedAgent {
11
+ id: string;
12
+ name: string;
13
+ }
14
+ export interface CompanionPairing {
15
+ /** A pairing exists on disk (a stored agent id) — i.e. `foundr login` has run. */
16
+ paired: boolean;
17
+ agent?: PairedAgent;
18
+ mcpUrl?: string;
19
+ hasToken?: boolean;
20
+ }
21
+ export type LiveErrorKind = 'auth' | 'network' | 'other';
22
+ export interface CompanionPairingVerification extends CompanionPairing {
23
+ /** The stored token actually works right now (heartbeat succeeded). */
24
+ live: boolean;
25
+ /** Why `live` is false while `paired` is true. */
26
+ liveError?: LiveErrorKind;
27
+ reason?: string;
28
+ }
29
+ /**
30
+ * One-line value for the `paired:` row of `foundr status`. When `live` is
31
+ * `undefined` the caller did a local-only check (`--local`), so we don't claim
32
+ * anything about whether the token still works.
33
+ */
34
+ export declare function pairingStatusLine(v: CompanionPairing | CompanionPairingVerification): string;
35
+ /** Trailing line for `foundr install`, conditioned on the local pairing. */
36
+ export declare function installPairingLine(p: CompanionPairing): string;
37
+ export type LoginDecision = {
38
+ action: 'already-paired';
39
+ lines: string[];
40
+ } | {
41
+ action: 'pair';
42
+ lines: string[];
43
+ };
44
+ /**
45
+ * Decide whether `foundr login` should short-circuit because the machine is
46
+ * already paired, or proceed with the interactive pairing flow.
47
+ *
48
+ * Re-pairing (which opens a browser) happens ONLY when the user clearly wants
49
+ * it — `--force`, a brand-new machine, or a `--url` pointing at a different
50
+ * origin than the stored pairing. When a pairing exists but the live check
51
+ * didn't confirm it (expired token OR a transient network/other failure) we do
52
+ * NOT silently re-pair: a blip must never surprise the user with a browser or
53
+ * throw away working credentials. We report the state and point at `--force`.
54
+ */
55
+ export declare function decideLogin(v: CompanionPairingVerification, opts?: {
56
+ force?: boolean;
57
+ originChanged?: boolean;
58
+ }): LoginDecision;
59
+ //# sourceMappingURL=pairing-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pairing-status.d.ts","sourceRoot":"","sources":["../src/pairing-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,gBAAgB;IAC/B,kFAAkF;IAClF,MAAM,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAA;AAExD,MAAM,WAAW,4BAA6B,SAAQ,gBAAgB;IACpE,uEAAuE;IACvE,IAAI,EAAE,OAAO,CAAA;IACb,kDAAkD;IAClD,SAAS,CAAC,EAAE,aAAa,CAAA;IACzB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAMD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,gBAAgB,GAAG,4BAA4B,GAAG,MAAM,CAU5F;AAED,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAI9D;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,MAAM,EAAE,gBAAgB,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GAC7C;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AAEvC;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CACzB,CAAC,EAAE,4BAA4B,EAC/B,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAO,GACtD,aAAa,CA+Bf"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Pure rendering + decision logic for the companion's pairing state.
3
+ *
4
+ * Kept free of any I/O so the `foundr login` / `install` / `status` UX is fully
5
+ * testable. The bridge daemon supplies the data (`readLocalPairing` for the
6
+ * no-network check, `verifyCompanionPairing` for the live heartbeat check); this
7
+ * module turns that data into the exact lines the CLI prints and the decision of
8
+ * whether `login` should short-circuit.
9
+ */
10
+ function who(agent) {
11
+ return agent ? `${agent.name} (${agent.id})` : 'this machine';
12
+ }
13
+ /**
14
+ * One-line value for the `paired:` row of `foundr status`. When `live` is
15
+ * `undefined` the caller did a local-only check (`--local`), so we don't claim
16
+ * anything about whether the token still works.
17
+ */
18
+ export function pairingStatusLine(v) {
19
+ if (!v.paired)
20
+ return 'no — run: foundr login';
21
+ const label = who(v.agent);
22
+ const live = v.live;
23
+ if (live === undefined)
24
+ return label;
25
+ if (live)
26
+ return `${label} — verified`;
27
+ const kind = v.liveError;
28
+ if (kind === 'auth')
29
+ return `${label} — sign-in expired, re-pair: foundr login`;
30
+ if (kind === 'network')
31
+ return `${label} — credentials present (couldn't verify — offline?)`;
32
+ return `${label} — credentials present (couldn't verify)`;
33
+ }
34
+ /** Trailing line for `foundr install`, conditioned on the local pairing. */
35
+ export function installPairingLine(p) {
36
+ return p.paired
37
+ ? `Paired as ${who(p.agent)}.`
38
+ : 'Not paired yet — run `foundr login` to pair.';
39
+ }
40
+ /**
41
+ * Decide whether `foundr login` should short-circuit because the machine is
42
+ * already paired, or proceed with the interactive pairing flow.
43
+ *
44
+ * Re-pairing (which opens a browser) happens ONLY when the user clearly wants
45
+ * it — `--force`, a brand-new machine, or a `--url` pointing at a different
46
+ * origin than the stored pairing. When a pairing exists but the live check
47
+ * didn't confirm it (expired token OR a transient network/other failure) we do
48
+ * NOT silently re-pair: a blip must never surprise the user with a browser or
49
+ * throw away working credentials. We report the state and point at `--force`.
50
+ */
51
+ export function decideLogin(v, opts = {}) {
52
+ const label = who(v.agent);
53
+ if (opts.force) {
54
+ return { action: 'pair', lines: v.paired ? [`Re-pairing ${label}…`] : [] };
55
+ }
56
+ if (opts.originChanged && v.paired) {
57
+ return {
58
+ action: 'pair',
59
+ lines: [`Pairing to a different Founder World origin (this machine was paired as ${label}).`],
60
+ };
61
+ }
62
+ if (!v.paired)
63
+ return { action: 'pair', lines: [] };
64
+ if (v.live) {
65
+ return {
66
+ action: 'already-paired',
67
+ lines: [`✓ Already paired as ${label}.`, 'Re-pair with: foundr login --force'],
68
+ };
69
+ }
70
+ if (v.liveError === 'auth') {
71
+ return {
72
+ action: 'already-paired',
73
+ lines: [`Already paired as ${label}, but the saved sign-in has expired.`, 'Re-pair with: foundr login --force'],
74
+ };
75
+ }
76
+ return {
77
+ action: 'already-paired',
78
+ lines: [
79
+ `Already paired as ${label} (couldn't reach Founder World to verify).`,
80
+ 'Re-pair with: foundr login --force',
81
+ ],
82
+ };
83
+ }
84
+ //# sourceMappingURL=pairing-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pairing-status.js","sourceRoot":"","sources":["../src/pairing-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAyBH,SAAS,GAAG,CAAC,KAAmB;IAC9B,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,cAAc,CAAA;AAC/D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,CAAkD;IAClF,IAAI,CAAC,CAAC,CAAC,MAAM;QAAE,OAAO,wBAAwB,CAAA;IAC9C,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;IAC1B,MAAM,IAAI,GAAI,CAAkC,CAAC,IAAI,CAAA;IACrD,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,KAAK,CAAA;IACpC,IAAI,IAAI;QAAE,OAAO,GAAG,KAAK,aAAa,CAAA;IACtC,MAAM,IAAI,GAAI,CAAkC,CAAC,SAAS,CAAA;IAC1D,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,GAAG,KAAK,2CAA2C,CAAA;IAC/E,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,GAAG,KAAK,qDAAqD,CAAA;IAC5F,OAAO,GAAG,KAAK,0CAA0C,CAAA;AAC3D,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,kBAAkB,CAAC,CAAmB;IACpD,OAAO,CAAC,CAAC,MAAM;QACb,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG;QAC9B,CAAC,CAAC,8CAA8C,CAAA;AACpD,CAAC;AAMD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CACzB,CAA+B,EAC/B,OAAqD,EAAE;IAEvD,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;IAC1B,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,cAAc,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;IAC5E,CAAC;IACD,IAAI,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;QACnC,OAAO;YACL,MAAM,EAAE,MAAM;YACd,KAAK,EAAE,CAAC,2EAA2E,KAAK,IAAI,CAAC;SAC9F,CAAA;IACH,CAAC;IACD,IAAI,CAAC,CAAC,CAAC,MAAM;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAA;IACnD,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACX,OAAO;YACL,MAAM,EAAE,gBAAgB;YACxB,KAAK,EAAE,CAAC,uBAAuB,KAAK,GAAG,EAAE,oCAAoC,CAAC;SAC/E,CAAA;IACH,CAAC;IACD,IAAI,CAAC,CAAC,SAAS,KAAK,MAAM,EAAE,CAAC;QAC3B,OAAO;YACL,MAAM,EAAE,gBAAgB;YACxB,KAAK,EAAE,CAAC,qBAAqB,KAAK,sCAAsC,EAAE,oCAAoC,CAAC;SAChH,CAAA;IACH,CAAC;IACD,OAAO;QACL,MAAM,EAAE,gBAAgB;QACxB,KAAK,EAAE;YACL,qBAAqB,KAAK,4CAA4C;YACtE,oCAAoC;SACrC;KACF,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foundr-companion",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"