foundr-companion 0.1.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.
- package/dist/bridge/adapters.d.mts +33 -0
- package/dist/bridge/adapters.d.mts.map +1 -0
- package/dist/bridge/adapters.mjs +159 -0
- package/dist/bridge/adapters.mjs.map +1 -0
- package/dist/bridge/bridge-auth.d.mts +5 -0
- package/dist/bridge/bridge-auth.d.mts.map +1 -0
- package/dist/bridge/bridge-auth.mjs +24 -0
- package/dist/bridge/bridge-auth.mjs.map +1 -0
- package/dist/bridge/codex-app-server-adapter.d.mts +37 -0
- package/dist/bridge/codex-app-server-adapter.d.mts.map +1 -0
- package/dist/bridge/codex-app-server-adapter.mjs +401 -0
- package/dist/bridge/codex-app-server-adapter.mjs.map +1 -0
- package/dist/bridge/daemon.mjs +190 -0
- package/dist/bridge/foundr-codex-reply.d.mts +96 -0
- package/dist/bridge/foundr-codex-reply.d.mts.map +1 -0
- package/dist/bridge/foundr-codex-reply.mjs +542 -0
- package/dist/bridge/foundr-codex-reply.mjs.map +1 -0
- package/dist/bridge/listener-flags.d.mts +5 -0
- package/dist/bridge/listener-flags.d.mts.map +1 -0
- package/dist/bridge/listener-flags.mjs +18 -0
- package/dist/bridge/listener-flags.mjs.map +1 -0
- package/dist/bridge/listener-loop.d.mts +58 -0
- package/dist/bridge/listener-loop.d.mts.map +1 -0
- package/dist/bridge/listener-loop.mjs +424 -0
- package/dist/bridge/listener-loop.mjs.map +1 -0
- package/dist/bridge/logout.d.mts +8 -0
- package/dist/bridge/logout.d.mts.map +1 -0
- package/dist/bridge/logout.mjs +35 -0
- package/dist/bridge/logout.mjs.map +1 -0
- package/dist/bridge/mcp-client.d.mts +97 -0
- package/dist/bridge/mcp-client.d.mts.map +1 -0
- package/dist/bridge/mcp-client.mjs +290 -0
- package/dist/bridge/mcp-client.mjs.map +1 -0
- package/dist/bridge/oauth-provider.d.mts +32 -0
- package/dist/bridge/oauth-provider.d.mts.map +1 -0
- package/dist/bridge/oauth-provider.mjs +94 -0
- package/dist/bridge/oauth-provider.mjs.map +1 -0
- package/dist/bridge/public-room-mention-listener-loop.d.mts +120 -0
- package/dist/bridge/public-room-mention-listener-loop.d.mts.map +1 -0
- package/dist/bridge/public-room-mention-listener-loop.mjs +225 -0
- package/dist/bridge/public-room-mention-listener-loop.mjs.map +1 -0
- package/dist/bridge/realtime-wake.d.mts +11 -0
- package/dist/bridge/realtime-wake.d.mts.map +1 -0
- package/dist/bridge/realtime-wake.mjs +134 -0
- package/dist/bridge/realtime-wake.mjs.map +1 -0
- package/dist/bridge/work-mission-listener-loop.d.mts +100 -0
- package/dist/bridge/work-mission-listener-loop.d.mts.map +1 -0
- package/dist/bridge/work-mission-listener-loop.mjs +737 -0
- package/dist/bridge/work-mission-listener-loop.mjs.map +1 -0
- package/dist/cli-parse.d.ts +27 -0
- package/dist/cli-parse.d.ts.map +1 -0
- package/dist/cli-parse.js +47 -0
- package/dist/cli-parse.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +232 -0
- package/dist/cli.js.map +1 -0
- package/dist/codex-preflight.d.ts +44 -0
- package/dist/codex-preflight.d.ts.map +1 -0
- package/dist/codex-preflight.js +74 -0
- package/dist/codex-preflight.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/launchd.d.ts +78 -0
- package/dist/launchd.d.ts.map +1 -0
- package/dist/launchd.js +118 -0
- package/dist/launchd.js.map +1 -0
- package/dist/paths.d.ts +30 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +26 -0
- package/dist/paths.js.map +1 -0
- package/install.sh +117 -0
- package/package.json +29 -0
package/dist/launchd.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* macOS LaunchAgent (launchd) support for the Foundr Companion daemon.
|
|
3
|
+
*
|
|
4
|
+
* Renders the per-user `.plist` and wraps the *modern* `launchctl` domain API
|
|
5
|
+
* (`enable` / `bootstrap` / `bootout` / `kickstart` / `print`). Shape mirrors the
|
|
6
|
+
* proven OpenClaw gateway LaunchAgent.
|
|
7
|
+
*
|
|
8
|
+
* Critical invariants baked into the plist:
|
|
9
|
+
* - `RunAtLoad` true so the daemon comes up at login.
|
|
10
|
+
* - `KeepAlive` is `{ SuccessfulExit: false }` — restart on crash, but DON'T
|
|
11
|
+
* hot-loop a clean exit (a deliberate config-error exit should stay down).
|
|
12
|
+
* - `EnvironmentVariables` ALWAYS carries `FOUNDR_CODEX_THREAD_MODE=bridge`. A
|
|
13
|
+
* launchd job has no `CODEX_THREAD_ID`, so resume mode would crash on boot.
|
|
14
|
+
* - All interpolated paths are ABSOLUTE — launchd starts jobs with a minimal env
|
|
15
|
+
* and no working directory inheritance.
|
|
16
|
+
*/
|
|
17
|
+
import { execFile as nodeExecFile } from 'node:child_process';
|
|
18
|
+
import { promisify } from 'node:util';
|
|
19
|
+
const defaultExecFile = promisify(nodeExecFile);
|
|
20
|
+
/** XML-escape a value for safe interpolation into plist `<string>` / `<key>`. */
|
|
21
|
+
function plistEscape(value) {
|
|
22
|
+
return value
|
|
23
|
+
.replaceAll('&', '&')
|
|
24
|
+
.replaceAll('<', '<')
|
|
25
|
+
.replaceAll('>', '>')
|
|
26
|
+
.replaceAll('"', '"')
|
|
27
|
+
.replaceAll("'", ''');
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build the LaunchAgent plist XML. Pure — no filesystem or process access.
|
|
31
|
+
*/
|
|
32
|
+
export function renderLaunchAgentPlist({ label, nodePath, cliJsPath, paths, env, }) {
|
|
33
|
+
const programArguments = [nodePath, cliJsPath, 'run'];
|
|
34
|
+
const argsXml = programArguments
|
|
35
|
+
.map((arg) => `\n <string>${plistEscape(arg)}</string>`)
|
|
36
|
+
.join('');
|
|
37
|
+
// FOUNDR_CODEX_THREAD_MODE=bridge first, then caller-provided keys. A caller
|
|
38
|
+
// key of the same name overrides, but the default guarantees presence.
|
|
39
|
+
const environment = Object.assign({ FOUNDR_CODEX_THREAD_MODE: 'bridge' }, (env !== null && env !== void 0 ? env : {}));
|
|
40
|
+
const envXml = Object.entries(environment)
|
|
41
|
+
.map(([key, value]) => `\n <key>${plistEscape(key)}</key>\n <string>${plistEscape(value)}</string>`)
|
|
42
|
+
.join('');
|
|
43
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
44
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
45
|
+
<plist version="1.0">
|
|
46
|
+
<dict>
|
|
47
|
+
<key>Label</key>
|
|
48
|
+
<string>${plistEscape(label)}</string>
|
|
49
|
+
<key>ProgramArguments</key>
|
|
50
|
+
<array>${argsXml}
|
|
51
|
+
</array>
|
|
52
|
+
<key>RunAtLoad</key>
|
|
53
|
+
<true/>
|
|
54
|
+
<key>KeepAlive</key>
|
|
55
|
+
<dict>
|
|
56
|
+
<key>SuccessfulExit</key>
|
|
57
|
+
<false/>
|
|
58
|
+
</dict>
|
|
59
|
+
<key>ThrottleInterval</key>
|
|
60
|
+
<integer>10</integer>
|
|
61
|
+
<key>ExitTimeOut</key>
|
|
62
|
+
<integer>20</integer>
|
|
63
|
+
<key>ProcessType</key>
|
|
64
|
+
<string>Interactive</string>
|
|
65
|
+
<key>StandardInPath</key>
|
|
66
|
+
<string>/dev/null</string>
|
|
67
|
+
<key>StandardOutPath</key>
|
|
68
|
+
<string>${plistEscape(paths.logFile)}</string>
|
|
69
|
+
<key>StandardErrorPath</key>
|
|
70
|
+
<string>${plistEscape(paths.errLogFile)}</string>
|
|
71
|
+
<key>EnvironmentVariables</key>
|
|
72
|
+
<dict>${envXml}
|
|
73
|
+
</dict>
|
|
74
|
+
</dict>
|
|
75
|
+
</plist>
|
|
76
|
+
`;
|
|
77
|
+
}
|
|
78
|
+
/** Default GUI domain uid — the current process uid on a real macOS session. */
|
|
79
|
+
function defaultUid() {
|
|
80
|
+
return typeof process.getuid === 'function' ? process.getuid() : 501;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Enable + bootstrap the LaunchAgent into the user's GUI domain.
|
|
84
|
+
* launchctl enable gui/<uid>/<label>
|
|
85
|
+
* launchctl bootstrap gui/<uid> <plistPath>
|
|
86
|
+
*/
|
|
87
|
+
export async function installLaunchAgent({ plistPath, label, uid = defaultUid(), execFile = defaultExecFile, }) {
|
|
88
|
+
await execFile('launchctl', ['enable', `gui/${uid}/${label}`]);
|
|
89
|
+
await execFile('launchctl', ['bootstrap', `gui/${uid}`, plistPath]);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Tear the LaunchAgent out of the GUI domain.
|
|
93
|
+
* launchctl bootout gui/<uid>/<label>
|
|
94
|
+
*/
|
|
95
|
+
export async function uninstallLaunchAgent({ label, uid = defaultUid(), execFile = defaultExecFile, }) {
|
|
96
|
+
await execFile('launchctl', ['bootout', `gui/${uid}/${label}`]);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Restart the running service in place.
|
|
100
|
+
* launchctl kickstart -k gui/<uid>/<label>
|
|
101
|
+
*/
|
|
102
|
+
export async function restartLaunchAgent({ label, uid = defaultUid(), execFile = defaultExecFile, }) {
|
|
103
|
+
await execFile('launchctl', ['kickstart', '-k', `gui/${uid}/${label}`]);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Whether the LaunchAgent is bootstrapped (loaded) in the GUI domain.
|
|
107
|
+
* launchctl print gui/<uid>/<label> (exit 0 => loaded)
|
|
108
|
+
*/
|
|
109
|
+
export async function isLaunchAgentLoaded({ label, uid = defaultUid(), execFile = defaultExecFile, }) {
|
|
110
|
+
try {
|
|
111
|
+
await execFile('launchctl', ['print', `gui/${uid}/${label}`]);
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
catch (_a) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=launchd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launchd.js","sourceRoot":"","sources":["../src/launchd.ts"],"names":[],"mappings":"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"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Reverse-DNS LaunchAgent label for the companion daemon. */
|
|
2
|
+
export declare const LAUNCH_AGENT_LABEL = "world.foundr.companion";
|
|
3
|
+
/**
|
|
4
|
+
* Canonical on-disk locations for the Foundr Companion.
|
|
5
|
+
*
|
|
6
|
+
* - `installRoot` (~/.foundr) is companion-owned scratch: logs, status, the
|
|
7
|
+
* `bin/foundr` shim. The npm-global package itself lives wherever npm put it.
|
|
8
|
+
* - `configDir` (~/.foundr-world) is shared with the legacy CLI bridge and holds
|
|
9
|
+
* the OAuth tokens (`bridge-auth.json`, 0600) and the Codex bridge thread id.
|
|
10
|
+
* - `launchAgentPlist` is the per-user LaunchAgent.
|
|
11
|
+
*
|
|
12
|
+
* Everything is derived from `home` so it is trivially testable.
|
|
13
|
+
*/
|
|
14
|
+
export interface CompanionPaths {
|
|
15
|
+
home: string;
|
|
16
|
+
installRoot: string;
|
|
17
|
+
binDir: string;
|
|
18
|
+
binShim: string;
|
|
19
|
+
logsDir: string;
|
|
20
|
+
logFile: string;
|
|
21
|
+
errLogFile: string;
|
|
22
|
+
statusFile: string;
|
|
23
|
+
configDir: string;
|
|
24
|
+
authFile: string;
|
|
25
|
+
codexThreadStore: string;
|
|
26
|
+
launchAgentsDir: string;
|
|
27
|
+
launchAgentPlist: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function companionPaths(home?: string): CompanionPaths;
|
|
30
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAGA,8DAA8D;AAC9D,eAAO,MAAM,kBAAkB,2BAA2B,CAAA;AAE1D;;;;;;;;;;GAUG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,gBAAgB,EAAE,MAAM,CAAA;IACxB,eAAe,EAAE,MAAM,CAAA;IACvB,gBAAgB,EAAE,MAAM,CAAA;CACzB;AAED,wBAAgB,cAAc,CAAC,IAAI,GAAE,MAAqB,GAAG,cAAc,CAoB1E"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/** Reverse-DNS LaunchAgent label for the companion daemon. */
|
|
4
|
+
export const LAUNCH_AGENT_LABEL = 'world.foundr.companion';
|
|
5
|
+
export function companionPaths(home = os.homedir()) {
|
|
6
|
+
const installRoot = path.join(home, '.foundr');
|
|
7
|
+
const logsDir = path.join(installRoot, 'logs');
|
|
8
|
+
const configDir = path.join(home, '.foundr-world');
|
|
9
|
+
const launchAgentsDir = path.join(home, 'Library', 'LaunchAgents');
|
|
10
|
+
return {
|
|
11
|
+
home,
|
|
12
|
+
installRoot,
|
|
13
|
+
binDir: path.join(installRoot, 'bin'),
|
|
14
|
+
binShim: path.join(installRoot, 'bin', 'foundr'),
|
|
15
|
+
logsDir,
|
|
16
|
+
logFile: path.join(logsDir, 'companion.log'),
|
|
17
|
+
errLogFile: path.join(logsDir, 'companion.err.log'),
|
|
18
|
+
statusFile: path.join(installRoot, 'status.json'),
|
|
19
|
+
configDir,
|
|
20
|
+
authFile: path.join(configDir, 'bridge-auth.json'),
|
|
21
|
+
codexThreadStore: path.join(configDir, 'codex-bridge-thread.json'),
|
|
22
|
+
launchAgentsDir,
|
|
23
|
+
launchAgentPlist: path.join(launchAgentsDir, `${LAUNCH_AGENT_LABEL}.plist`),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,8DAA8D;AAC9D,MAAM,CAAC,MAAM,kBAAkB,GAAG,wBAAwB,CAAA;AA6B1D,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,CAAC,OAAO,EAAE;IACxD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;IAC9C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC,CAAA;IAClD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,cAAc,CAAC,CAAA;IAClE,OAAO;QACL,IAAI;QACJ,WAAW;QACX,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC;QACrC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,QAAQ,CAAC;QAChD,OAAO;QACP,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC;QAC5C,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,mBAAmB,CAAC;QACnD,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC;QACjD,SAAS;QACT,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC;QAClD,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,0BAA0B,CAAC;QAClE,eAAe;QACf,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,kBAAkB,QAAQ,CAAC;KAC5E,CAAA;AACH,CAAC"}
|
package/install.sh
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Foundr Companion installer.
|
|
5
|
+
#
|
|
6
|
+
# curl -fsSL https://www.foundr.world/install.sh | bash
|
|
7
|
+
#
|
|
8
|
+
# Installs the `foundr-companion` npm package globally, wires up the per-user
|
|
9
|
+
# LaunchAgent (`foundr install`), runs the Codex preflight (`foundr codex`),
|
|
10
|
+
# and prints next steps. Idempotent: re-running upgrades in place.
|
|
11
|
+
#
|
|
12
|
+
# The entire body lives in main() and is only invoked on the very last line,
|
|
13
|
+
# so a truncated download can never execute a half-written script.
|
|
14
|
+
|
|
15
|
+
main() {
|
|
16
|
+
FOUNDR_VERSION="${FOUNDR_VERSION:-latest}"
|
|
17
|
+
FOUNDR_URL="${FOUNDR_URL:-https://www.foundr.world}"
|
|
18
|
+
|
|
19
|
+
say() { printf 'foundr> %s\n' "$1"; }
|
|
20
|
+
warn() { printf 'foundr! %s\n' "$1" >&2; }
|
|
21
|
+
die() { printf 'foundr x %s\n' "$1" >&2; exit 1; }
|
|
22
|
+
|
|
23
|
+
say "Installing Foundr Companion (version: ${FOUNDR_VERSION})"
|
|
24
|
+
say "Origin: ${FOUNDR_URL}"
|
|
25
|
+
|
|
26
|
+
# --- (2) Ensure Node >= 22.19 ------------------------------------------
|
|
27
|
+
need_node_install=0
|
|
28
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
29
|
+
warn "Node.js not found."
|
|
30
|
+
need_node_install=1
|
|
31
|
+
else
|
|
32
|
+
node_version="$(node -v 2>/dev/null | sed 's/^v//')"
|
|
33
|
+
node_major="${node_version%%.*}"
|
|
34
|
+
rest="${node_version#*.}"
|
|
35
|
+
node_minor="${rest%%.*}"
|
|
36
|
+
case "$node_major" in
|
|
37
|
+
''|*[!0-9]*) node_major=0 ;;
|
|
38
|
+
esac
|
|
39
|
+
case "$node_minor" in
|
|
40
|
+
''|*[!0-9]*) node_minor=0 ;;
|
|
41
|
+
esac
|
|
42
|
+
if [ "$node_major" -lt 22 ] || { [ "$node_major" -eq 22 ] && [ "$node_minor" -lt 19 ]; }; then
|
|
43
|
+
warn "Node ${node_version} is too old (need >= 22.19)."
|
|
44
|
+
need_node_install=1
|
|
45
|
+
else
|
|
46
|
+
say "Node ${node_version} OK (>= 22.19)."
|
|
47
|
+
fi
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
if [ "$need_node_install" -eq 1 ]; then
|
|
51
|
+
if [ "$(uname -s)" = "Darwin" ] && command -v brew >/dev/null 2>&1; then
|
|
52
|
+
say "Installing Node via Homebrew (brew install node)..."
|
|
53
|
+
brew install node
|
|
54
|
+
else
|
|
55
|
+
die "Please install Node.js >= 22.19 from https://nodejs.org and re-run this installer."
|
|
56
|
+
fi
|
|
57
|
+
command -v node >/dev/null 2>&1 || die "Node still not on PATH after install. Open a new shell and re-run."
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# --- (2b) Ensure a writable npm global prefix (never sudo) -------------
|
|
61
|
+
warn_no_sudo() { warn "Never run 'sudo npm -g' — it leaves root-owned files in your home dir. We are fixing the prefix instead."; }
|
|
62
|
+
|
|
63
|
+
npm_prefix="$(npm config get prefix 2>/dev/null || echo '')"
|
|
64
|
+
prefix_writable=1
|
|
65
|
+
if [ -n "$npm_prefix" ] && [ -d "$npm_prefix" ]; then
|
|
66
|
+
if [ ! -w "$npm_prefix" ]; then prefix_writable=0; fi
|
|
67
|
+
elif [ -n "$npm_prefix" ]; then
|
|
68
|
+
parent="$(dirname "$npm_prefix")"
|
|
69
|
+
if [ ! -w "$parent" ]; then prefix_writable=0; fi
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
if [ "$prefix_writable" -eq 0 ]; then
|
|
73
|
+
warn_no_sudo
|
|
74
|
+
user_prefix="$HOME/.npm-global"
|
|
75
|
+
say "npm global prefix ('$npm_prefix') is not writable. Switching to a user-owned prefix: ${user_prefix}"
|
|
76
|
+
npm config set prefix "$user_prefix"
|
|
77
|
+
mkdir -p "$user_prefix/bin"
|
|
78
|
+
# Persist on PATH via ~/.npmrc-adjacent shell config and print an export line.
|
|
79
|
+
npmrc="$HOME/.npmrc"
|
|
80
|
+
if [ ! -f "$npmrc" ] || ! grep -q "^prefix=" "$npmrc" 2>/dev/null; then
|
|
81
|
+
printf 'prefix=%s\n' "$user_prefix" >> "$npmrc"
|
|
82
|
+
fi
|
|
83
|
+
case ":$PATH:" in
|
|
84
|
+
*":$user_prefix/bin:"*) ;;
|
|
85
|
+
*) PATH="$user_prefix/bin:$PATH"; export PATH ;;
|
|
86
|
+
esac
|
|
87
|
+
say "Add this to your shell profile (~/.zshrc or ~/.bashrc) so 'foundr' is always on PATH:"
|
|
88
|
+
printf '\n export PATH="%s/bin:$PATH"\n\n' "$user_prefix"
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# --- (3) Install the package globally ----------------------------------
|
|
92
|
+
say "Installing foundr-companion@${FOUNDR_VERSION} globally (this also upgrades an existing install)..."
|
|
93
|
+
env -u NPM_CONFIG_BEFORE -u NPM_CONFIG_MIN_RELEASE_AGE \
|
|
94
|
+
npm install -g "foundr-companion@${FOUNDR_VERSION}" --no-fund --no-audit
|
|
95
|
+
|
|
96
|
+
command -v foundr >/dev/null 2>&1 || die "'foundr' not found on PATH after install. If you just set a new npm prefix, open a new shell (or run the export line above) and re-run."
|
|
97
|
+
|
|
98
|
+
# --- (4) Set up the daemon + preflight ---------------------------------
|
|
99
|
+
say "Setting up the LaunchAgent and starting the companion (foundr install)..."
|
|
100
|
+
foundr install
|
|
101
|
+
|
|
102
|
+
say "Running the Codex preflight (foundr codex)..."
|
|
103
|
+
foundr codex
|
|
104
|
+
|
|
105
|
+
# --- (5) Next steps ----------------------------------------------------
|
|
106
|
+
say "Done. Three steps to start talking to your agent:"
|
|
107
|
+
printf '\n'
|
|
108
|
+
printf ' 1) Pair with Founder World: foundr login\n'
|
|
109
|
+
printf ' (opens %s to authorize this machine)\n' "$FOUNDR_URL"
|
|
110
|
+
printf ' 2) Sign in to Codex: codex login\n'
|
|
111
|
+
printf ' (choose "Sign in with ChatGPT")\n'
|
|
112
|
+
printf ' 3) Message your agent in the game at %s\n' "$FOUNDR_URL"
|
|
113
|
+
printf '\n'
|
|
114
|
+
say "Re-run this installer anytime to upgrade in place."
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
main "$@"
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "foundr-companion",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"bin": {
|
|
10
|
+
"foundr": "./dist/cli.js"
|
|
11
|
+
},
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"install.sh"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=22.19.0"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc -p tsconfig.build.json && node copy-bridge.mjs",
|
|
23
|
+
"test": "vitest run"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
27
|
+
"@supabase/supabase-js": "^2.105.4"
|
|
28
|
+
}
|
|
29
|
+
}
|