foundr-companion 0.1.0 → 0.1.2
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/dist/bridge/bridge-auth.d.mts +20 -0
- package/dist/bridge/bridge-auth.d.mts.map +1 -1
- package/dist/bridge/bridge-auth.mjs +18 -0
- package/dist/bridge/bridge-auth.mjs.map +1 -1
- package/dist/bridge/daemon.mjs +148 -7
- package/dist/bridge/mcp-client.d.mts +1 -0
- package/dist/bridge/mcp-client.d.mts.map +1 -1
- package/dist/bridge/mcp-client.mjs +17 -5
- package/dist/bridge/mcp-client.mjs.map +1 -1
- package/dist/bridge/oauth-provider.d.mts +3 -1
- package/dist/bridge/oauth-provider.d.mts.map +1 -1
- package/dist/bridge/oauth-provider.mjs +6 -2
- package/dist/bridge/oauth-provider.mjs.map +1 -1
- package/dist/cli.js +50 -27
- package/dist/cli.js.map +1 -1
- package/dist/pairing-status.d.ts +59 -0
- package/dist/pairing-status.d.ts.map +1 -0
- package/dist/pairing-status.js +84 -0
- package/dist/pairing-status.js.map +1 -0
- package/package.json +1 -1
|
@@ -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"}
|
package/dist/bridge/daemon.mjs
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
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'
|
|
9
|
-
import { createMcpClient, withVercelProtectionBypass } from './mcp-client.mjs'
|
|
8
|
+
import { loadBridgeAuth, saveBridgeAuth, deleteBridgeAuth, readLocalPairing } from './bridge-auth.mjs'
|
|
9
|
+
import { createMcpClient, createOAuthCallbackWaiter, withVercelProtectionBypass } from './mcp-client.mjs'
|
|
10
10
|
import { FileBackedOAuthProvider } from './oauth-provider.mjs'
|
|
11
11
|
import { logoutFoundrBridge } from './logout.mjs'
|
|
12
12
|
import { createCodexAppServerAdapter } from './codex-app-server-adapter.mjs'
|
|
@@ -42,9 +42,15 @@ export async function loginCompanion({
|
|
|
42
42
|
onRedirect,
|
|
43
43
|
log = console.log,
|
|
44
44
|
} = {}) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
// `login` is an explicit (re)pairing: register a fresh client whose loopback
|
|
46
|
+
// redirect URI uses a free OS-assigned port. This means a stale/in-use port
|
|
47
|
+
// (e.g. a previous login that left its callback bound) can never block login
|
|
48
|
+
// — the root cause of the 17893 EADDRINUSE. We bind the callback FIRST so its
|
|
49
|
+
// port is known before client registration builds the redirect URI.
|
|
50
|
+
const callback = createOAuthCallbackWaiter()
|
|
51
|
+
await callback.ready
|
|
52
|
+
|
|
53
|
+
let pairedAgent
|
|
48
54
|
const persistAuth = async (nextAuth) => {
|
|
49
55
|
await saveBridgeAuth({
|
|
50
56
|
...nextAuth,
|
|
@@ -57,14 +63,19 @@ export async function loginCompanion({
|
|
|
57
63
|
const provider = new FileBackedOAuthProvider({
|
|
58
64
|
mcpUrl,
|
|
59
65
|
agentName,
|
|
60
|
-
auth,
|
|
66
|
+
auth: {},
|
|
67
|
+
redirectPort: callback.port,
|
|
61
68
|
onChange: persistAuth,
|
|
62
69
|
onRedirect: onRedirect ?? ((url) => {
|
|
63
70
|
log(`Open this URL to authorize the Foundr Companion:\n${withVercelProtectionBypass(url).toString()}`)
|
|
64
71
|
}),
|
|
65
72
|
})
|
|
66
73
|
|
|
67
|
-
const mcp = await createMcpClient({
|
|
74
|
+
const mcp = await createMcpClient({
|
|
75
|
+
mcpUrl,
|
|
76
|
+
authProvider: provider,
|
|
77
|
+
oauthCallbackFactory: () => callback,
|
|
78
|
+
})
|
|
68
79
|
try {
|
|
69
80
|
const heartbeat = await mcp.callTool('heartbeat_private_chat_listener', {
|
|
70
81
|
client_name: CLIENT_NAME,
|
|
@@ -75,6 +86,7 @@ export async function loginCompanion({
|
|
|
75
86
|
await persistAuth(provider.auth)
|
|
76
87
|
return { agent: heartbeat.agent }
|
|
77
88
|
} finally {
|
|
89
|
+
callback.close()
|
|
78
90
|
await mcp.close()
|
|
79
91
|
}
|
|
80
92
|
}
|
|
@@ -83,6 +95,135 @@ export async function logoutCompanion() {
|
|
|
83
95
|
await logoutFoundrBridge({ loadAuth: loadBridgeAuth, deleteAuth: deleteBridgeAuth })
|
|
84
96
|
}
|
|
85
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 = 8000 } = {}) {
|
|
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
|
+
|
|
86
227
|
function isProcessAlive(pid) {
|
|
87
228
|
if (!Number.isInteger(pid) || pid <= 0) return false
|
|
88
229
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-client.d.mts","sourceRoot":"","sources":["../../src/bridge/mcp-client.mjs"],"names":[],"mappings":"AAOA
|
|
1
|
+
{"version":3,"file":"mcp-client.d.mts","sourceRoot":"","sources":["../../src/bridge/mcp-client.mjs"],"names":[],"mappings":"AAOA;;;;;;;EAqGC;AAED;;iBAEC;AAED,+FAUC;AAED,iDAOC;AAED,0DAQC;AAiCD;;;iBA8BC;AA2BD,kDAOC;AAcD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CC;8CA1S6C,oDAAoD;uBAF3E,2CAA2C"}
|
|
@@ -5,10 +5,16 @@ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/
|
|
|
5
5
|
|
|
6
6
|
const CLIENT_INFO = { name: 'foundr-local-bridge', version: '0.1.0' }
|
|
7
7
|
|
|
8
|
-
export function createOAuthCallbackWaiter({ port =
|
|
8
|
+
export function createOAuthCallbackWaiter({ port = 0 } = {}) {
|
|
9
|
+
// Default port 0 = let the OS assign a free loopback port. A hardcoded port
|
|
10
|
+
// (the old 17893) collides whenever anything already holds it — a previous
|
|
11
|
+
// login that didn't finish, a second instance, etc. — and bricks login for
|
|
12
|
+
// every founder, not just the first. The actual bound port is read back from
|
|
13
|
+
// the listening socket and used as the OAuth redirect URI.
|
|
9
14
|
let server
|
|
10
15
|
let settled = false
|
|
11
16
|
let readySettled = false
|
|
17
|
+
let actualPort = port
|
|
12
18
|
let resolveReady
|
|
13
19
|
let rejectReady
|
|
14
20
|
|
|
@@ -16,7 +22,7 @@ export function createOAuthCallbackWaiter({ port = 17893 } = {}) {
|
|
|
16
22
|
resolveReady = () => {
|
|
17
23
|
if (readySettled) return
|
|
18
24
|
readySettled = true
|
|
19
|
-
resolve()
|
|
25
|
+
resolve(actualPort)
|
|
20
26
|
}
|
|
21
27
|
rejectReady = (error) => {
|
|
22
28
|
if (readySettled) return
|
|
@@ -58,7 +64,7 @@ export function createOAuthCallbackWaiter({ port = 17893 } = {}) {
|
|
|
58
64
|
|
|
59
65
|
server = createServer((req, res) => {
|
|
60
66
|
try {
|
|
61
|
-
const url = new URL(req.url ?? '/',
|
|
67
|
+
const url = new URL(req.url ?? '/', 'http://127.0.0.1')
|
|
62
68
|
const oauthError = url.searchParams.get('error')
|
|
63
69
|
const errorDescription = url.searchParams.get('error_description')
|
|
64
70
|
const authCode = url.searchParams.get('code')
|
|
@@ -81,13 +87,19 @@ export function createOAuthCallbackWaiter({ port = 17893 } = {}) {
|
|
|
81
87
|
})
|
|
82
88
|
|
|
83
89
|
server.on('error', (error) => settle(rejectCode, error))
|
|
84
|
-
server.listen(port, '127.0.0.1',
|
|
90
|
+
server.listen(port, '127.0.0.1', () => {
|
|
91
|
+
actualPort = server.address()?.port ?? port
|
|
92
|
+
resolveReady()
|
|
93
|
+
})
|
|
85
94
|
})
|
|
86
95
|
void code.catch(() => {})
|
|
87
96
|
|
|
88
97
|
return {
|
|
89
98
|
ready,
|
|
90
99
|
code,
|
|
100
|
+
get port() {
|
|
101
|
+
return actualPort
|
|
102
|
+
},
|
|
91
103
|
close() {
|
|
92
104
|
if (settled) return
|
|
93
105
|
settled = true
|
|
@@ -96,7 +108,7 @@ export function createOAuthCallbackWaiter({ port = 17893 } = {}) {
|
|
|
96
108
|
}
|
|
97
109
|
}
|
|
98
110
|
|
|
99
|
-
export function waitForOAuthCallback({ port =
|
|
111
|
+
export function waitForOAuthCallback({ port = 0 } = {}) {
|
|
100
112
|
return createOAuthCallbackWaiter({ port }).code
|
|
101
113
|
}
|
|
102
114
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-client.mjs","sourceRoot":"","sources":["../../src/bridge/mcp-client.mjs"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAA;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAA;AAC5E,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAA;AAElG,MAAM,WAAW,GAAG,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,OAAO,EAAE,CAAA;AAErE,MAAM,UAAU,yBAAyB,CAAC,EAAE,IAAI,GAAG,
|
|
1
|
+
{"version":3,"file":"mcp-client.mjs","sourceRoot":"","sources":["../../src/bridge/mcp-client.mjs"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAA;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAA;AAC5E,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAA;AAElG,MAAM,WAAW,GAAG,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,OAAO,EAAE,CAAA;AAErE,MAAM,UAAU,yBAAyB,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,GAAG,EAAE;IACzD,4EAA4E;IAC5E,2EAA2E;IAC3E,2EAA2E;IAC3E,6EAA6E;IAC7E,2DAA2D;IAC3D,IAAI,MAAM,CAAA;IACV,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,IAAI,YAAY,GAAG,KAAK,CAAA;IACxB,IAAI,UAAU,GAAG,IAAI,CAAA;IACrB,IAAI,YAAY,CAAA;IAChB,IAAI,WAAW,CAAA;IAEf,MAAM,KAAK,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC5C,YAAY,GAAG,GAAG,EAAE;YAClB,IAAI,YAAY;gBAAE,OAAM;YACxB,YAAY,GAAG,IAAI,CAAA;YACnB,OAAO,CAAC,UAAU,CAAC,CAAA;QACrB,CAAC,CAAA;QACD,WAAW,GAAG,CAAC,KAAK,EAAE,EAAE;YACtB,IAAI,YAAY;gBAAE,OAAM;YACxB,YAAY,GAAG,IAAI,CAAA;YACnB,MAAM,CAAC,KAAK,CAAC,CAAA;QACf,CAAC,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,MAAM,WAAW,GAAG,CAAC,OAAO,GAAG,GAAG,EAAE,GAAE,CAAC,EAAE,EAAE;QACzC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,EAAE,CAAA;YACT,OAAM;QACR,CAAC;QACD,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;YACrB,OAAM;QACR,CAAC;QACD,OAAO,EAAE,CAAA;IACX,CAAC,CAAA;IAED,MAAM,kBAAkB,GAAG,GAAG,EAAE;QAC9B,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,MAAM,CAAC,KAAK,EAAE,CAAA;YACd,OAAM;QACR,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAA;IAChD,CAAC,CAAA;IAED,MAAM,IAAI,GAAG,IAAI,OAAO,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE;QACnD,MAAM,MAAM,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE;YAC3B,IAAI,OAAO;gBAAE,OAAM;YACnB,OAAO,GAAG,IAAI,CAAA;YACd,IAAI,EAAE,KAAK,UAAU,EAAE,CAAC;gBACtB,WAAW,CAAC,KAAK,CAAC,CAAA;YACpB,CAAC;YACD,WAAW,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;QAC9B,CAAC,CAAA;QAED,MAAM,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;;YACjC,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAA,GAAG,CAAC,GAAG,mCAAI,GAAG,EAAE,kBAAkB,CAAC,CAAA;gBACvD,MAAM,UAAU,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;gBAChD,MAAM,gBAAgB,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAA;gBAClE,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;gBAE7C,IAAI,UAAU,EAAE,CAAC;oBACf,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,UAAU,KAAK,gBAAgB,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;gBACvF,CAAC;gBACD,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAA;gBACvC,CAAC;gBAED,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,2BAA2B,EAAE,CAAC,CAAA;gBACnE,GAAG,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAA;gBACpE,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;YAC/B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,2BAA2B,EAAE,CAAC,CAAA;gBACnE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;gBACtE,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,CAAA;YAC3B,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAA;QACxD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE;;YACpC,UAAU,GAAG,MAAA,MAAA,MAAM,CAAC,OAAO,EAAE,0CAAE,IAAI,mCAAI,IAAI,CAAA;YAC3C,YAAY,EAAE,CAAA;QAChB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IACF,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;IAEzB,OAAO;QACL,KAAK;QACL,IAAI;QACJ,IAAI,IAAI;YACN,OAAO,UAAU,CAAA;QACnB,CAAC;QACD,KAAK;YACH,IAAI,OAAO;gBAAE,OAAM;YACnB,OAAO,GAAG,IAAI,CAAA;YACd,kBAAkB,EAAE,CAAA;QACtB,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,GAAG,EAAE;IACpD,OAAO,yBAAyB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAA;AACjD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAM,EAAE,YAAY;IAClD,MAAM,gBAAgB,GAAG,sBAAsB,EAAE,CAAA;IACjD,MAAM,WAAW,GAAG,gBAAgB;QAClC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,4BAA4B,EAAE,gBAAgB,EAAE,EAAE;QACjE,CAAC,CAAC,SAAS,CAAA;IAEb,OAAO,IAAI,6BAA6B,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,kBACtD,YAAY,IACT,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EACvC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,OAAO,CACL,OAAO,CAAC,GAAG,CAAC,+BAA+B;QAC3C,OAAO,CAAC,GAAG,CAAC,+BAA+B;QAC3C,OAAO,CAAC,GAAG,CAAC,wBAAwB;QACpC,EAAE,CACH,CAAC,IAAI,EAAE,CAAA;AACV,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,GAAG;IAC5C,MAAM,gBAAgB,GAAG,sBAAsB,EAAE,CAAA;IACjD,IAAI,CAAC,gBAAgB;QAAE,OAAO,GAAG,CAAA;IAEjC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAA;IACvC,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,4BAA4B,EAAE,gBAAgB,CAAC,CAAA;IACxE,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,4BAA4B,EAAE,MAAM,CAAC,CAAA;IAC9D,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,MAAM,EAAE,IAAI;IACjC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAA;IACrC,OAAO,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAA;AACzC,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,QAAQ;IACvC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;IAClC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAA;IACpB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IAC1B,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE;IAC5C,MAAM,IAAI,GAAG,OAAO,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,IAAI,CAAA,KAAK,QAAQ;QAC5C,CAAC,CAAC,OAAO,CAAC,IAAI;QACd,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;YAClD,CAAC,CAAC,aAAa;YACf,CAAC,CAAC,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAA;IAC/B,MAAM,OAAO,GAAG,OAAO,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,OAAO,CAAA,KAAK,QAAQ;QAClD,CAAC,CAAC,OAAO,CAAC,OAAO;QACjB,CAAC,CAAC,QAAQ,CAAC,UAAU,IAAI,4BAA4B,CAAA;IACvD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC,CAAA;IAC9C,KAAK,CAAC,IAAI,GAAG,IAAI,CAAA;IACjB,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAA;IAC9B,KAAK,CAAC,OAAO,GAAG,OAAO,CAAA;IACvB,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,EACnC,MAAM,EACN,YAAY,EACZ,IAAI,EACJ,IAAI,GAAG,EAAE,EACT,SAAS,GAAG,UAAU,CAAC,KAAK,GAC7B,GAAG,EAAE;;IACJ,MAAM,WAAW,GAAG,MAAA,MAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,MAAM,4DAAI,0CAAE,YAAY,CAAA;IAC1D,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;QAC5D,KAAK,CAAC,IAAI,GAAG,aAAa,CAAA;QAC1B,MAAM,KAAK,CAAA;IACb,CAAC;IAED,MAAM,OAAO,GAAG;QACd,MAAM,EAAE,kBAAkB;QAC1B,aAAa,EAAE,UAAU,WAAW,EAAE;QACtC,cAAc,EAAE,kBAAkB;KACnC,CAAA;IACD,MAAM,gBAAgB,GAAG,sBAAsB,EAAE,CAAA;IACjD,IAAI,gBAAgB;QAAE,OAAO,CAAC,4BAA4B,CAAC,GAAG,gBAAgB,CAAA;IAE9E,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE;QAC5D,MAAM,EAAE,MAAM;QACd,OAAO;QACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CAAA;IACF,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,QAAQ,CAAC,CAAA;IACjD,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,MAAM,eAAe,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAA;IAC9D,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAM;;IAC9B,OAAO,MAAA,MAAA,MAAA,MAAA,MAAM,CAAC,OAAO,0CAAE,IAAI,CACzB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,IAAI,MAAK,MAAM,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CACjE,0CAAE,IAAI,0CAAE,IAAI,EAAE,mCAAI,EAAE,CAAA;AACvB,CAAC;AAED,SAAS,cAAc,CAAC,IAAI;IAC1B,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAA;IAC3B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAM;;IAC9B,MAAM,IAAI,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;IACrC,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAA;IACnC,MAAM,IAAI,GAAG,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,IAAI,mCAAI,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,0CAAE,IAAI,CAAA;IAChD,MAAM,OAAO,GAAG,MAAA,MAAA,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,OAAO,mCAAI,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,0CAAE,OAAO,mCAAI,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,mCAAI,IAAI,CAAA;IAElF,IAAI,IAAI,IAAI,OAAO;QAAE,OAAO,GAAG,IAAI,KAAK,OAAO,EAAE,CAAA;IACjD,OAAO,OAAO,IAAI,4BAA4B,CAAA;AAChD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAM;IACpC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAA;IAC3C,CAAC;IAED,MAAM,IAAI,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;IACrC,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;AACrC,CAAC;AAED,SAAS,6BAA6B,CAAC,YAAY,EAAE,gBAAgB;IACnE,IAAI,CAAC,YAAY;QAAE,OAAO,YAAY,CAAA;IAEtC,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;IAC5C,QAAQ,CAAC,uBAAuB,GAAG,KAAK,EAAE,GAAG,EAAE,EAAE;;QAC/C,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAA;QACxC,MAAM,aAAa,CAAC,KAAK,CAAA;QACzB,OAAO,MAAA,YAAY,CAAC,uBAAuB,6DAAG,GAAG,CAAC,CAAA;IACpD,CAAC,CAAA;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,EACpC,MAAM,EACN,YAAY,EACZ,aAAa,GAAG,GAAG,EAAE,CAAC,IAAI,MAAM,CAAC,WAAW,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,EACnE,gBAAgB,GAAG,eAAe,EAClC,oBAAoB,GAAG,yBAAyB,GACjD,GAAG,EAAE;IACJ,MAAM,MAAM,GAAG,aAAa,EAAE,CAAA;IAC9B,IAAI,oBAAoB,CAAA;IACxB,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC5B,oBAAoB,aAApB,oBAAoB,cAApB,oBAAoB,IAApB,oBAAoB,GAAK,oBAAoB,EAAE,EAAA;QAC/C,OAAO,oBAAoB,CAAA;IAC7B,CAAC,CAAA;IACD,MAAM,uBAAuB,GAAG,6BAA6B,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;IAC7F,IAAI,SAAS,GAAG,gBAAgB,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAA;IAEjE,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;QAC/B,oBAAoB,aAApB,oBAAoB,uBAApB,oBAAoB,CAAE,KAAK,EAAE,CAAA;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,CAAC,KAAK,YAAY,iBAAiB,CAAC,EAAE,CAAC;YAC1C,oBAAoB,aAApB,oBAAoB,uBAApB,oBAAoB,CAAE,KAAK,EAAE,CAAA;YAC7B,MAAM,KAAK,CAAA;QACb,CAAC;QAED,MAAM,aAAa,GAAG,oBAAoB,aAApB,oBAAoB,cAApB,oBAAoB,GAAI,gBAAgB,EAAE,CAAA;QAChE,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,IAAI,CAAA;QACzC,MAAM,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAA;QACpC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QAEpC,oBAAoB,GAAG,SAAS,CAAA;QAChC,SAAS,GAAG,gBAAgB,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAA;QAC7D,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IACjC,CAAC;IAED,OAAO;QACL,MAAM;QACN,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,EAAE;YAC5B,OAAO,eAAe,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;QAC1E,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,EAAE;YAC5B,OAAO,cAAc,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QAC7D,CAAC;QACD,KAAK,CAAC,KAAK;YACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;QACtB,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
export class FileBackedOAuthProvider {
|
|
2
|
-
constructor({ mcpUrl, agentName, auth, onRedirect, onChange }?: {
|
|
2
|
+
constructor({ mcpUrl, agentName, auth, onRedirect, onChange, redirectPort }?: {
|
|
3
3
|
agentName?: string | undefined;
|
|
4
4
|
auth?: {} | undefined;
|
|
5
|
+
redirectPort?: number | undefined;
|
|
5
6
|
});
|
|
6
7
|
mcpUrl: any;
|
|
7
8
|
agentName: string;
|
|
8
9
|
auth: {};
|
|
9
10
|
onRedirect: any;
|
|
10
11
|
onChange: any;
|
|
12
|
+
redirectPort: number;
|
|
11
13
|
get redirectUrl(): string;
|
|
12
14
|
get clientMetadata(): {
|
|
13
15
|
client_name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-provider.d.mts","sourceRoot":"","sources":["../../src/bridge/oauth-provider.mjs"],"names":[],"mappings":"AAOA;IACE
|
|
1
|
+
{"version":3,"file":"oauth-provider.d.mts","sourceRoot":"","sources":["../../src/bridge/oauth-provider.mjs"],"names":[],"mappings":"AAOA;IACE;;;;OAUC;IATC,YAAoB;IACpB,kBAA0B;IAC1B,SAAsB;IACtB,gBAA4B;IAC5B,cAAwB;IAIxB,qBAAgC;IAGlC,0BAEC;IAED;;;;;;;MASC;IAED,yBAEC;IAED,8BAEC;IAED,gDAGC;IAED,cAEC;IAED,uCAGC;IAED,uCAEC;IAED,+CAGC;IAED,oBAKC;IAED,8CAGC;IAED,sBAEC;IAED,iDAcC;CACF"}
|
|
@@ -6,16 +6,20 @@ function bridgeScope() {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export class FileBackedOAuthProvider {
|
|
9
|
-
constructor({ mcpUrl, agentName = 'Local Agent', auth = {}, onRedirect, onChange } = {}) {
|
|
9
|
+
constructor({ mcpUrl, agentName = 'Local Agent', auth = {}, onRedirect, onChange, redirectPort = 17893 } = {}) {
|
|
10
10
|
this.mcpUrl = mcpUrl
|
|
11
11
|
this.agentName = agentName
|
|
12
12
|
this.auth = auth ?? {}
|
|
13
13
|
this.onRedirect = onRedirect
|
|
14
14
|
this.onChange = onChange
|
|
15
|
+
// The loopback OAuth redirect port. Set to the actual free port the callback
|
|
16
|
+
// server bound (see createOAuthCallbackWaiter) so the registered redirect URI
|
|
17
|
+
// matches the listener and never depends on a fixed, collidable port.
|
|
18
|
+
this.redirectPort = redirectPort
|
|
15
19
|
}
|
|
16
20
|
|
|
17
21
|
get redirectUrl() {
|
|
18
|
-
return
|
|
22
|
+
return `http://127.0.0.1:${this.redirectPort}/callback`
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
get clientMetadata() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-provider.mjs","sourceRoot":"","sources":["../../src/bridge/oauth-provider.mjs"],"names":[],"mappings":"AAAA,MAAM,kBAAkB,GAAG,CAAC,WAAW,EAAE,aAAa,EAAE,mBAAmB,CAAC,CAAA;AAE5E,SAAS,WAAW;IAClB,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IACrE,OAAO,UAAU,IAAI,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,OAAO,uBAAuB;IAClC,YAAY,EAAE,MAAM,EAAE,SAAS,GAAG,aAAa,EAAE,IAAI,GAAG,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE;
|
|
1
|
+
{"version":3,"file":"oauth-provider.mjs","sourceRoot":"","sources":["../../src/bridge/oauth-provider.mjs"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -3,11 +3,12 @@ import fs from 'node:fs/promises';
|
|
|
3
3
|
import { spawn } from 'node:child_process';
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import { parseCli, readOption } from './cli-parse.js';
|
|
6
|
+
import { parseCli, readOption, hasFlag } from './cli-parse.js';
|
|
7
7
|
import { companionPaths, LAUNCH_AGENT_LABEL } from './paths.js';
|
|
8
8
|
import { installLaunchAgent, isLaunchAgentLoaded, renderLaunchAgentPlist, restartLaunchAgent, uninstallLaunchAgent, } from './launchd.js';
|
|
9
9
|
import { codexPreflight } from './codex-preflight.js';
|
|
10
|
-
import { DEFAULT_MCP_URL, loginCompanion, logoutCompanion, resolveMcpUrl, startCompanionDaemon, } from './bridge/daemon.mjs';
|
|
10
|
+
import { DEFAULT_MCP_URL, loginCompanion, logoutCompanion, readLocalPairing, resolveMcpUrl, startCompanionDaemon, verifyCompanionPairing, } from './bridge/daemon.mjs';
|
|
11
|
+
import { decideLogin, installPairingLine, pairingStatusLine } from './pairing-status.js';
|
|
11
12
|
const require = createRequire(import.meta.url);
|
|
12
13
|
const VERSION = require('../package.json').version;
|
|
13
14
|
// dist/cli.js at runtime — the absolute path launchd should exec.
|
|
@@ -21,7 +22,8 @@ function usage() {
|
|
|
21
22
|
'Usage: foundr <command>',
|
|
22
23
|
'',
|
|
23
24
|
'Setup:',
|
|
24
|
-
' login Pair this machine with Founder World (opens a browser)',
|
|
25
|
+
' login Pair this machine with Founder World (opens a browser).',
|
|
26
|
+
' Detects an existing pairing; use --force to re-pair.',
|
|
25
27
|
' codex Check your Codex CLI login (Sign in with ChatGPT)',
|
|
26
28
|
' install Install + start the background service (launchd)',
|
|
27
29
|
'',
|
|
@@ -41,6 +43,8 @@ function usage() {
|
|
|
41
43
|
' --url <origin> Founder World origin (default https://www.foundr.world).',
|
|
42
44
|
' Also honored via FOUNDR_URL. Use a *.lab.foundr.world',
|
|
43
45
|
' origin to target a lab deploy.',
|
|
46
|
+
' --force With `login`: re-pair even if already paired.',
|
|
47
|
+
' --local With `status`: skip the online check (on-disk state only).',
|
|
44
48
|
].join('\n');
|
|
45
49
|
}
|
|
46
50
|
function run(cmd, args) {
|
|
@@ -52,7 +56,26 @@ function run(cmd, args) {
|
|
|
52
56
|
}
|
|
53
57
|
async function cmdLogin(args) {
|
|
54
58
|
var _a, _b;
|
|
55
|
-
const
|
|
59
|
+
const force = hasFlag(args, '--force') || hasFlag(args, '--relogin');
|
|
60
|
+
// Detect an existing pairing before re-running OAuth.
|
|
61
|
+
const local = await readLocalPairing();
|
|
62
|
+
// A bare `login` re-verifies the EXISTING pairing's origin (fall back to it),
|
|
63
|
+
// so a lab-paired machine isn't silently re-pointed at the prod default. Only
|
|
64
|
+
// an explicit --url / FOUNDR_URL counts as a deliberate origin change.
|
|
65
|
+
const explicitUrl = (_a = readOption(args, '--url')) !== null && _a !== void 0 ? _a : process.env.FOUNDR_URL;
|
|
66
|
+
const mcpUrl = resolveMcpUrl((_b = explicitUrl !== null && explicitUrl !== void 0 ? explicitUrl : local.mcpUrl) !== null && _b !== void 0 ? _b : DEFAULT_MCP_URL);
|
|
67
|
+
// The live check only short-circuits when targeting the SAME origin we're
|
|
68
|
+
// paired to. If --url points elsewhere (or there's no pairing, or --force),
|
|
69
|
+
// skip the round-trip and let decideLogin route to pairing — otherwise a live
|
|
70
|
+
// heartbeat against the OLD origin would falsely block a deliberate re-point.
|
|
71
|
+
const originChanged = Boolean(explicitUrl && local.paired && local.mcpUrl && resolveMcpUrl(local.mcpUrl) !== mcpUrl);
|
|
72
|
+
const current = force || originChanged || !local.paired
|
|
73
|
+
? Object.assign(Object.assign({}, local), { live: false }) : await verifyCompanionPairing();
|
|
74
|
+
const decision = decideLogin(current, { force, originChanged });
|
|
75
|
+
for (const line of decision.lines)
|
|
76
|
+
console.log(line);
|
|
77
|
+
if (decision.action === 'already-paired')
|
|
78
|
+
return 0;
|
|
56
79
|
const { agent } = await loginCompanion({ mcpUrl });
|
|
57
80
|
console.log(`Paired as ${agent.name} (${agent.id}).`);
|
|
58
81
|
console.log('Next: run `foundr install` to start the background service.');
|
|
@@ -66,12 +89,15 @@ async function cmdCodex() {
|
|
|
66
89
|
console.log(' • ' + g);
|
|
67
90
|
return pf.ok ? 0 : 1;
|
|
68
91
|
}
|
|
69
|
-
async function writePlistAndLoad() {
|
|
92
|
+
async function writePlistAndLoad(urlOverride) {
|
|
70
93
|
const paths = companionPaths();
|
|
71
94
|
await fs.mkdir(paths.logsDir, { recursive: true });
|
|
72
95
|
await fs.mkdir(paths.launchAgentsDir, { recursive: true });
|
|
73
96
|
const env = {};
|
|
74
|
-
|
|
97
|
+
// The listener prefers the origin stored at pairing time (auth.mcpUrl); this
|
|
98
|
+
// plist env is the fallback. Honor an explicit --url so `install --url …`
|
|
99
|
+
// isn't silently ignored, as the global help implies it's supported.
|
|
100
|
+
const url = urlOverride !== null && urlOverride !== void 0 ? urlOverride : process.env.FOUNDR_URL;
|
|
75
101
|
if (url)
|
|
76
102
|
env.FOUNDR_URL = url;
|
|
77
103
|
const plist = renderLaunchAgentPlist({
|
|
@@ -89,18 +115,20 @@ async function writePlistAndLoad() {
|
|
|
89
115
|
await installLaunchAgent({ plistPath: paths.launchAgentPlist, label: LAUNCH_AGENT_LABEL });
|
|
90
116
|
}
|
|
91
117
|
}
|
|
92
|
-
async function cmdInstall() {
|
|
93
|
-
await writePlistAndLoad();
|
|
118
|
+
async function cmdInstall(args) {
|
|
119
|
+
await writePlistAndLoad(readOption(args, '--url'));
|
|
94
120
|
console.log('Installed and started the Foundr companion (launchd).');
|
|
95
121
|
const pf = await codexPreflight();
|
|
96
122
|
if (!pf.ok)
|
|
97
123
|
for (const g of pf.guidance)
|
|
98
124
|
console.log(' • ' + g);
|
|
99
|
-
|
|
125
|
+
// Report the actual pairing state instead of a blanket "if not paired" hint.
|
|
126
|
+
// Local read only — keep install fast and offline-safe.
|
|
127
|
+
console.log(installPairingLine(await readLocalPairing()));
|
|
100
128
|
return 0;
|
|
101
129
|
}
|
|
102
|
-
async function cmdStart() {
|
|
103
|
-
await writePlistAndLoad();
|
|
130
|
+
async function cmdStart(args) {
|
|
131
|
+
await writePlistAndLoad(readOption(args, '--url'));
|
|
104
132
|
console.log('Started.');
|
|
105
133
|
return 0;
|
|
106
134
|
}
|
|
@@ -127,23 +155,18 @@ async function cmdUninstall() {
|
|
|
127
155
|
console.log('Credentials remain in ~/.foundr-world — run `foundr logout` to clear them.');
|
|
128
156
|
return 0;
|
|
129
157
|
}
|
|
130
|
-
async function cmdStatus() {
|
|
131
|
-
var _a
|
|
132
|
-
const paths = companionPaths();
|
|
158
|
+
async function cmdStatus(args) {
|
|
159
|
+
var _a;
|
|
133
160
|
const loaded = await isLaunchAgentLoaded({ label: LAUNCH_AGENT_LABEL });
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
catch (_c) {
|
|
140
|
-
paired = null;
|
|
141
|
-
}
|
|
161
|
+
// Default to a live check (heartbeat) so `paired:` reflects reality; --local
|
|
162
|
+
// / --no-verify skips the network round-trip and reports the on-disk state.
|
|
163
|
+
const localOnly = hasFlag(args, '--local') || hasFlag(args, '--no-verify');
|
|
164
|
+
const pairing = localOnly ? await readLocalPairing() : await verifyCompanionPairing();
|
|
142
165
|
const pf = await codexPreflight();
|
|
143
166
|
console.log('Foundr companion');
|
|
144
|
-
console.log(` paired: ${
|
|
167
|
+
console.log(` paired: ${pairingStatusLine(pairing)}`);
|
|
145
168
|
console.log(` service: ${loaded ? 'running (launchd)' : 'not installed — run: foundr install'}`);
|
|
146
|
-
console.log(` codex: ${pf.ok ? `ready (${(
|
|
169
|
+
console.log(` codex: ${pf.ok ? `ready (${(_a = pf.authMode) !== null && _a !== void 0 ? _a : 'unknown'})` : 'not ready'}`);
|
|
147
170
|
for (const g of pf.guidance)
|
|
148
171
|
console.log(' • ' + g);
|
|
149
172
|
return 0;
|
|
@@ -202,17 +225,17 @@ async function main() {
|
|
|
202
225
|
case 'codex':
|
|
203
226
|
return cmdCodex();
|
|
204
227
|
case 'install':
|
|
205
|
-
return cmdInstall();
|
|
228
|
+
return cmdInstall(parsed.args);
|
|
206
229
|
case 'uninstall':
|
|
207
230
|
return cmdUninstall();
|
|
208
231
|
case 'start':
|
|
209
|
-
return cmdStart();
|
|
232
|
+
return cmdStart(parsed.args);
|
|
210
233
|
case 'stop':
|
|
211
234
|
return cmdStop();
|
|
212
235
|
case 'restart':
|
|
213
236
|
return cmdRestart();
|
|
214
237
|
case 'status':
|
|
215
|
-
return cmdStatus();
|
|
238
|
+
return cmdStatus(parsed.args);
|
|
216
239
|
case 'update':
|
|
217
240
|
return cmdUpdate();
|
|
218
241
|
case 'run':
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;
|
|
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"}
|