fuigo 0.0.1 → 1.0.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/README.md CHANGED
@@ -1,9 +1,61 @@
1
- # fuigo
1
+ # Fuigo
2
2
 
3
- **Fuigo** the agent execution engine behind [Murage](https://murage.ai).
3
+ Bring Fuigo into your terminal. Fast, flicker-free CLI built for plans, subagents, and parallel work.
4
4
 
5
- Named for the 鞴 (*fuigo*), the bellows of a Japanese tatara ironworks:
6
- the mechanism that supplies the force, worked under the direction of the
7
- 村下 (*murage*), the furnace master.
5
+ **[Homepage](https://x.ai/cli)** | **[Documentation](https://docs.x.ai/build/overview)**
8
6
 
9
- This package reserves the name. Implementation is in active development.
7
+ ## Install
8
+
9
+ ```bash
10
+ curl -fsSL https://x.ai/cli/install.sh | bash
11
+ ```
12
+
13
+ Or install with npm:
14
+
15
+ ```bash
16
+ npm i -g fuigo
17
+ ```
18
+
19
+ ## Get Started
20
+
21
+ ```bash
22
+ # Launch the interactive TUI
23
+ fuigo
24
+
25
+ # Run a single task
26
+ fuigo -p "Explain this codebase"
27
+ ```
28
+
29
+ On first launch, Fuigo opens your browser to authenticate. For CI or headless environments, use an API key from [console.x.ai](https://console.x.ai):
30
+
31
+ ```bash
32
+ export FUIGO_API_KEY="fuigo-..."
33
+ ```
34
+
35
+ ## Update
36
+
37
+ ```bash
38
+ fuigo update
39
+ ```
40
+
41
+ Or if installed via npm:
42
+
43
+ ```bash
44
+ npm i -g fuigo@latest
45
+ ```
46
+
47
+ ## Supported Platforms
48
+
49
+ | Platform | Architecture |
50
+ |---|---|
51
+ | macOS | Apple Silicon (arm64) |
52
+ | Linux | x86_64, arm64 |
53
+ | Windows | x86_64 |
54
+
55
+ ## Documentation
56
+
57
+ For full documentation including configuration, MCP servers, custom models, headless mode, agent mode, and more, visit [docs.x.ai/build/overview](https://docs.x.ai/build/overview).
58
+
59
+ ## Feedback
60
+
61
+ Run `/feedback` inside Fuigo to report issues or send feedback directly.
package/bin/fuigo ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ // On Unix npm installs, postinstall.js replaces this entry with a symlink to
3
+ // the sibling fuigo-native binary; every other install launches through node.
4
+ require('./fuigo-bootstrap.js');
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env node
2
+ // Resolves the fuigo binary and runs it, in order of preference:
3
+ // 1. $FUIGO_HOME/bin/fuigo, the versioned symlink postinstall.js installs
4
+ // 2. bootstrap it from the per-platform fuigo-<platform>
5
+ // package, decompressing the compressed binary into $FUIGO_HOME/bin
6
+ // 3. decompress in place under node_modules (no resolvable version, or
7
+ // an unwritable home)
8
+ //
9
+ // Binaries ship brotli-compressed to stay under npm's tarball size limit.
10
+ const { spawn } = require('child_process');
11
+ const path = require('path');
12
+ const fs = require('fs');
13
+ const os = require('os');
14
+ const zlib = require('zlib');
15
+
16
+ const pkgName = 'fuigo';
17
+ const IS_WINDOWS = process.platform === 'win32';
18
+ const EXE = IS_WINDOWS ? '.exe' : '';
19
+ const BIN_NAME = `fuigo${EXE}`;
20
+ // $FUIGO_HOME/bin (else ~/.fuigo/bin), matching the Rust fuigo_home():
21
+ // a symlinked $HOME resolves the same way.
22
+ function defaultFuigoHome() {
23
+ const home = os.homedir();
24
+ try { return path.join(fs.realpathSync(home), '.fuigo'); } catch { return path.join(home, '.fuigo'); }
25
+ }
26
+ const FUIGO_HOME = process.env.FUIGO_HOME ?? defaultFuigoHome();
27
+ const CANONICAL_DIR = path.join(FUIGO_HOME, 'bin');
28
+ const CANONICAL_PATH = path.join(CANONICAL_DIR, BIN_NAME);
29
+
30
+ function readLocalVersion() {
31
+ try { return require('../package.json').version; } catch { return undefined; }
32
+ }
33
+
34
+ // Returns null when npm skipped the matching optional dependency
35
+ // (unsupported platform, or --no-optional).
36
+ function resolvePlatformPackageDir() {
37
+ const platformPkg = `fuigo-${process.platform}-${process.arch}`;
38
+ try {
39
+ return path.dirname(require.resolve(`${platformPkg}/package.json`));
40
+ } catch {
41
+ return null;
42
+ }
43
+ }
44
+
45
+ function writeVendorBinary(brotliPath, binaryPath, destPath) {
46
+ const tmp = destPath + `.tmp.${process.pid}`;
47
+ try {
48
+ if (fs.existsSync(brotliPath)) {
49
+ fs.writeFileSync(tmp, zlib.brotliDecompressSync(fs.readFileSync(brotliPath)));
50
+ } else if (fs.existsSync(binaryPath)) {
51
+ fs.copyFileSync(binaryPath, tmp);
52
+ } else {
53
+ return false;
54
+ }
55
+ if (!IS_WINDOWS) fs.chmodSync(tmp, 0o755);
56
+ fs.renameSync(tmp, destPath);
57
+ return true;
58
+ } catch {
59
+ return false;
60
+ } finally {
61
+ try { fs.unlinkSync(tmp); } catch {}
62
+ }
63
+ }
64
+
65
+ function swapCanonical(versionedName, versionedPath) {
66
+ if (!IS_WINDOWS) {
67
+ const tmpLink = CANONICAL_PATH + `.link.${process.pid}`;
68
+ try { fs.unlinkSync(tmpLink); } catch {}
69
+ fs.symlinkSync(versionedName, tmpLink);
70
+ fs.renameSync(tmpLink, CANONICAL_PATH);
71
+ return;
72
+ }
73
+ const oldPath = CANONICAL_PATH + '.old';
74
+ try { fs.unlinkSync(oldPath); } catch {}
75
+ try {
76
+ try { fs.unlinkSync(CANONICAL_PATH); } catch {}
77
+ fs.copyFileSync(versionedPath, CANONICAL_PATH);
78
+ } catch {
79
+ fs.renameSync(CANONICAL_PATH, oldPath);
80
+ try {
81
+ fs.copyFileSync(versionedPath, CANONICAL_PATH);
82
+ } catch {
83
+ try { fs.renameSync(oldPath, CANONICAL_PATH); } catch {}
84
+ throw new Error('locked');
85
+ }
86
+ }
87
+ }
88
+
89
+ function bootstrapCanonical(brotliPath, binaryPath, version) {
90
+ try {
91
+ fs.mkdirSync(CANONICAL_DIR, { recursive: true });
92
+ const versionedName = `fuigo-${version}${EXE}`;
93
+ const versionedPath = path.join(CANONICAL_DIR, versionedName);
94
+ if (!fs.existsSync(versionedPath) && !writeVendorBinary(brotliPath, binaryPath, versionedPath)) {
95
+ return null;
96
+ }
97
+ swapCanonical(versionedName, versionedPath);
98
+ // null on a broken wire-up so the caller falls back to in-place launch.
99
+ return fs.existsSync(CANONICAL_PATH) ? CANONICAL_PATH : null;
100
+ } catch {
101
+ return null;
102
+ }
103
+ }
104
+
105
+ function resolveBinary() {
106
+ if (fs.existsSync(CANONICAL_PATH)) return CANONICAL_PATH;
107
+
108
+ const platformDir = resolvePlatformPackageDir();
109
+ if (!platformDir) {
110
+ console.error(`${pkgName}: no platform binary installed for ${process.platform}-${process.arch}.`);
111
+ console.error(` Expected sibling package fuigo-${process.platform}-${process.arch}.`);
112
+ console.error(` This usually means npm skipped optionalDependencies (e.g. --no-optional)`);
113
+ console.error(` or the platform is not supported.`);
114
+ process.exit(1);
115
+ }
116
+
117
+ const binaryPath = path.join(platformDir, 'bin', BIN_NAME);
118
+ const brotliPath = binaryPath + '.br';
119
+ const version = readLocalVersion();
120
+
121
+ if (version) {
122
+ const bootstrapped = bootstrapCanonical(brotliPath, binaryPath, version);
123
+ if (bootstrapped) return bootstrapped;
124
+ }
125
+
126
+ if (!fs.existsSync(binaryPath) && !writeVendorBinary(brotliPath, binaryPath, binaryPath)) {
127
+ console.error(`${pkgName}: missing binary at ${binaryPath}`);
128
+ process.exit(1);
129
+ }
130
+ return binaryPath;
131
+ }
132
+
133
+ const execPath = resolveBinary();
134
+ const childEnv = { ...process.env, FUIGO_MANAGED_BY_NPM: '1' };
135
+ const child = spawn(execPath, process.argv.slice(2), { stdio: 'inherit', env: childEnv });
136
+ child.on('exit', (code, signal) => {
137
+ if (signal) {
138
+ process.kill(process.pid, signal);
139
+ } else {
140
+ process.exit(code ?? 0);
141
+ }
142
+ });
@@ -0,0 +1,268 @@
1
+ #!/usr/bin/env node
2
+ // Runs once after npm install/update. Reads the fuigo binary from the
3
+ // matching per-platform optional dependency (fuigo-<platform>)
4
+ // and installs it to ~/.fuigo/bin/ using versioned filenames:
5
+ //
6
+ // Unix: fuigo-<version> + fuigo (symlink)
7
+ // Windows: fuigo-<version>.exe + fuigo.exe (copy)
8
+ //
9
+ // Versioned files ensure running processes are never disrupted on macOS
10
+ // (replacing a binary that a running process has mmap'd causes SIGKILL
11
+ // because the kernel can no longer verify the code signature).
12
+ const path = require('path');
13
+ const fs = require('fs');
14
+ const os = require('os');
15
+ const zlib = require('zlib');
16
+ const { execSync } = require('child_process');
17
+ const TOML = require('@iarna/toml');
18
+
19
+ // $FUIGO_HOME (else ~/.fuigo), matching the Rust fuigo_home(): a symlinked
20
+ // $HOME resolves the same way. Lets fleets relocate the binary off a slow $HOME
21
+ // (NFS); old code hardcoded os.homedir().
22
+ function defaultFuigoHome() {
23
+ const home = os.homedir();
24
+ try { return path.join(fs.realpathSync(home), '.fuigo'); } catch { return path.join(home, '.fuigo'); }
25
+ }
26
+ const FUIGO_HOME = process.env.FUIGO_HOME ?? defaultFuigoHome();
27
+ const CANONICAL_DIR = path.join(FUIGO_HOME, 'bin');
28
+
29
+ const key = `${process.platform}-${process.arch}`;
30
+ const SUPPORTED = new Set([
31
+ 'darwin-arm64',
32
+ 'darwin-x64',
33
+ 'linux-x64',
34
+ 'linux-arm64',
35
+ 'win32-x64',
36
+ 'win32-arm64',
37
+ ]);
38
+ if (!SUPPORTED.has(key)) {
39
+ console.error(`fuigo: unsupported platform ${key}`);
40
+ process.exit(0);
41
+ }
42
+
43
+ // Resolve the per-platform sibling package's directory. The matching
44
+ // optionalDependency is installed by npm based on `os`/`cpu` filters; the
45
+ // other five are silently skipped. If the matching one is missing, npm was
46
+ // likely invoked with --no-optional or the platform is unsupported.
47
+ function resolvePlatformPackageDir() {
48
+ const platformPkg = `fuigo-${key}`;
49
+ try {
50
+ return path.dirname(require.resolve(`${platformPkg}/package.json`));
51
+ } catch {
52
+ return null;
53
+ }
54
+ }
55
+
56
+ let version;
57
+ try { version = require('../package.json').version; } catch {}
58
+ if (!version) {
59
+ console.error('fuigo: unable to determine version');
60
+ process.exit(0);
61
+ }
62
+
63
+ const IS_WINDOWS = process.platform === 'win32';
64
+ const EXE = IS_WINDOWS ? '.exe' : '';
65
+
66
+ fs.mkdirSync(CANONICAL_DIR, { recursive: true });
67
+
68
+ function writeVendorBinary(brotliPath, binaryPath, destPath) {
69
+ const tmp = destPath + `.tmp.${process.pid}`;
70
+ try {
71
+ if (fs.existsSync(brotliPath)) {
72
+ fs.writeFileSync(tmp, zlib.brotliDecompressSync(fs.readFileSync(brotliPath)));
73
+ } else if (fs.existsSync(binaryPath)) {
74
+ fs.copyFileSync(binaryPath, tmp);
75
+ } else {
76
+ return false;
77
+ }
78
+ if (!IS_WINDOWS) fs.chmodSync(tmp, 0o755);
79
+ fs.renameSync(tmp, destPath);
80
+ return true;
81
+ } catch {
82
+ return false;
83
+ } finally {
84
+ try { fs.unlinkSync(tmp); } catch {}
85
+ }
86
+ }
87
+
88
+ function installBinary(binName, sourceDir, vendorSubpath) {
89
+ const brotliPath = path.join(sourceDir, 'bin', vendorSubpath + '.br');
90
+ const binaryPath = path.join(sourceDir, 'bin', vendorSubpath);
91
+
92
+ const versionedName = `${binName}-${version}${EXE}`;
93
+ const versionedPath = path.join(CANONICAL_DIR, versionedName);
94
+ const canonicalName = `${binName}${EXE}`;
95
+ const canonicalPath = path.join(CANONICAL_DIR, canonicalName);
96
+
97
+ // Skip if this exact version is already installed.
98
+ if (!fs.existsSync(versionedPath) && !writeVendorBinary(brotliPath, binaryPath, versionedPath)) {
99
+ console.error(`fuigo: missing binary at ${brotliPath}`);
100
+ return false;
101
+ }
102
+
103
+ if (IS_WINDOWS) {
104
+ // Symlinks need elevation on Windows; copy instead. If the exe is
105
+ // locked by a running process, rename it aside then retry.
106
+ const oldPath = canonicalPath + '.old';
107
+ try { fs.unlinkSync(oldPath); } catch {} // stale backup from prior update
108
+ try {
109
+ try { fs.unlinkSync(canonicalPath); } catch {}
110
+ fs.copyFileSync(versionedPath, canonicalPath);
111
+ } catch (e) {
112
+ try {
113
+ fs.renameSync(canonicalPath, oldPath);
114
+ try {
115
+ fs.copyFileSync(versionedPath, canonicalPath);
116
+ } catch (copyErr) {
117
+ // Rollback: restore the old binary so the install isn't broken.
118
+ try { fs.renameSync(oldPath, canonicalPath); } catch {}
119
+ throw copyErr;
120
+ }
121
+ } catch (e2) {
122
+ console.error(`fuigo: failed to update ${canonicalPath}: ${e2.message}`);
123
+ console.error('Close all running fuigo processes and try again.');
124
+ return false;
125
+ }
126
+ }
127
+ } else {
128
+ // Atomic symlink swap.
129
+ const tmpLink = canonicalPath + `.link.${process.pid}`;
130
+ try { fs.unlinkSync(tmpLink); } catch {}
131
+ fs.symlinkSync(versionedName, tmpLink);
132
+ fs.renameSync(tmpLink, canonicalPath);
133
+ }
134
+
135
+ // Don't report a broken wire-up as success.
136
+ if (!fs.existsSync(canonicalPath)) {
137
+ console.error(`fuigo: ${canonicalName} did not resolve after install`);
138
+ return false;
139
+ }
140
+
141
+ console.log(`${binName} ${version} installed to ${canonicalPath} -> ${versionedName}`);
142
+ return true;
143
+ }
144
+
145
+ // Comparator: sort "<prefix>X.Y.Z" filenames by version, newest first.
146
+ function byVersionDescending(prefix) {
147
+ return (a, b) => {
148
+ const pa = a.slice(prefix.length).split('.').map(Number);
149
+ const pb = b.slice(prefix.length).split('.').map(Number);
150
+ for (let i = 0; i < 3; i++) {
151
+ if ((pa[i] || 0) !== (pb[i] || 0)) return (pb[i] || 0) - (pa[i] || 0);
152
+ }
153
+ return 0;
154
+ };
155
+ }
156
+
157
+ // Best-effort cleanup of old versioned binaries for a given binary name.
158
+ // Keeps the current version and the previous one (in case a process is still
159
+ // running the old binary and hasn't fully loaded all pages yet).
160
+ // Uses an exact prefix match + hyphen + digit to avoid fuigo-* matching fuigo-pager-*.
161
+ function cleanupOldVersions(binName) {
162
+ try {
163
+ const prefix = `${binName}-`;
164
+ const currentVersioned = `${binName}-${version}${EXE}`;
165
+ const entries = fs.readdirSync(CANONICAL_DIR);
166
+ const versionedBinaries = entries
167
+ .filter(e => {
168
+ if (!e.startsWith(prefix)) return false;
169
+ if (e.includes('.tmp.') || e.includes('.link.')) return false;
170
+ if (e === currentVersioned) return false;
171
+ const suffix = e.slice(prefix.length);
172
+ return /^\d/.test(suffix);
173
+ })
174
+ .sort(byVersionDescending(prefix));
175
+ for (const old of versionedBinaries.slice(1)) {
176
+ try { fs.unlinkSync(path.join(CANONICAL_DIR, old)); } catch {}
177
+ }
178
+ } catch {}
179
+ }
180
+
181
+ const platformDir = resolvePlatformPackageDir();
182
+ if (!platformDir) {
183
+ console.error(`fuigo: platform package fuigo-${key} not installed.`);
184
+ console.error(' This usually means npm was invoked with --no-optional, or the install failed.');
185
+ console.error(' Try: npm install -g fuigo');
186
+ process.exit(0);
187
+ }
188
+
189
+ // Point the bin entry at a binary extracted beside it: launches become one
190
+ // process, and the link can only dangle if the package itself is broken.
191
+ // Windows keeps the node launcher; npm generates its command shims from it.
192
+ function installBinLink(platformDir) {
193
+ if (IS_WINDOWS) return;
194
+ // Other package managers wrap the entry's `#!` line in their own launchers.
195
+ if (!(process.env.npm_config_user_agent ?? '').startsWith('npm/')) return;
196
+ const brotliPath = path.join(platformDir, 'bin', `fuigo${EXE}.br`);
197
+ const binaryPath = path.join(platformDir, 'bin', `fuigo${EXE}`);
198
+ const nativePath = path.join(__dirname, 'fuigo-native');
199
+ const entryPath = path.join(__dirname, 'fuigo');
200
+ const tmp = entryPath + `.link.${process.pid}`;
201
+ try {
202
+ if (!writeVendorBinary(brotliPath, binaryPath, nativePath)) {
203
+ return;
204
+ }
205
+ try { fs.unlinkSync(tmp); } catch {}
206
+ fs.symlinkSync('./fuigo-native', tmp);
207
+ fs.renameSync(tmp, entryPath);
208
+ } catch (e) {
209
+ // Losing the link only costs latency; the node launcher still works.
210
+ console.error(`fuigo: bin link not installed: ${e.message}`);
211
+ try { fs.unlinkSync(tmp); } catch {}
212
+ }
213
+ }
214
+
215
+ if (installBinary('fuigo', platformDir, `fuigo${EXE}`)) {
216
+ installBinLink(platformDir);
217
+ }
218
+ cleanupOldVersions('fuigo');
219
+ cleanupOldVersions('fuigo-pager');
220
+
221
+ // Write installer config
222
+ const configDir = FUIGO_HOME;
223
+ const configPath = path.join(configDir, 'config.toml');
224
+ let obj = {};
225
+ try { obj = TOML.parse(fs.readFileSync(configPath, 'utf8')); } catch { }
226
+ obj.cli ??= {};
227
+ obj.cli.installer = 'npm';
228
+
229
+ // Persist the npm registry so `fuigo update` and the launcher use the same one.
230
+ const npmRegistry = process.env.FUIGO_NPM_REGISTRY
231
+ || (() => {
232
+ try {
233
+ const resolved = execSync(
234
+ 'npm config get registry',
235
+ { encoding: 'utf8', timeout: 5000 }
236
+ ).trim();
237
+ if (resolved && resolved !== 'undefined') return resolved;
238
+ } catch {}
239
+ return null;
240
+ })();
241
+
242
+ if (npmRegistry) {
243
+ obj.cli.npm_registry = npmRegistry;
244
+ }
245
+
246
+ fs.writeFileSync(configPath, TOML.stringify(obj), 'utf8');
247
+
248
+ // Shell completions: print setup hints (no silent shell config mutation).
249
+ // Set FUIGO_INSTALL_COMPLETIONS=1 to auto-generate to ~/.fuigo/completions.
250
+ const FUIGO_PATH = path.join(CANONICAL_DIR, `fuigo${EXE}`);
251
+ if (process.env.FUIGO_INSTALL_COMPLETIONS === '1' && !IS_WINDOWS) {
252
+ try {
253
+ const { spawnSync } = require('child_process');
254
+ const completionsDir = path.join(FUIGO_HOME, 'completions');
255
+ const bashPath = path.join(completionsDir, 'bash', 'fuigo.bash');
256
+ const zshPath = path.join(completionsDir, 'zsh', '_fuigo');
257
+ fs.mkdirSync(path.dirname(bashPath), { recursive: true });
258
+ fs.mkdirSync(path.dirname(zshPath), { recursive: true });
259
+ const bashRes = spawnSync(FUIGO_PATH, ['completions', 'bash'], { encoding: 'utf8' });
260
+ if (bashRes.status === 0) fs.writeFileSync(bashPath, bashRes.stdout);
261
+ const zshRes = spawnSync(FUIGO_PATH, ['completions', 'zsh'], { encoding: 'utf8' });
262
+ if (zshRes.status === 0) fs.writeFileSync(zshPath, zshRes.stdout);
263
+ console.log('Completions generated to ~/.fuigo/completions (bash/zsh)');
264
+ } catch {}
265
+ } else if (!IS_WINDOWS) {
266
+ console.log('Tip: fuigo completions bash > ~/.local/share/bash-completion/completions/fuigo');
267
+ console.log(' fuigo completions zsh > ~/.zsh/completions/_fuigo');
268
+ }
package/package.json CHANGED
@@ -1,21 +1,45 @@
1
1
  {
2
- "name": "fuigo",
3
- "version": "0.0.1",
4
- "description": "Fuigo \u2014 agent execution engine for Murage. Name reserved; implementation in development.",
5
- "homepage": "https://murage.ai",
6
- "license": "Apache-2.0",
7
- "keywords": [
8
- "agents",
9
- "engine",
10
- "orchestration",
11
- "ai"
12
- ],
13
- "main": "index.js",
14
- "files": [
15
- "index.js",
16
- "README.md"
17
- ],
18
- "publishConfig": {
19
- "access": "public"
20
- }
2
+ "name": "fuigo",
3
+ "version": "1.0.2",
4
+ "description": "Bring Fuigo into your terminal",
5
+ "license": "Apache-2.0",
6
+ "bin": {
7
+ "fuigo": "bin/fuigo"
8
+ },
9
+ "files": [
10
+ "bin/"
11
+ ],
12
+ "os": [
13
+ "darwin",
14
+ "linux",
15
+ "win32"
16
+ ],
17
+ "cpu": [
18
+ "arm64",
19
+ "x64"
20
+ ],
21
+ "scripts": {
22
+ "postinstall": "node bin/postinstall.js",
23
+ "sync-version": "node scripts/sync-version.js",
24
+ "check-version": "node scripts/sync-version.js --check",
25
+ "assemble": "node scripts/assemble-platform-packages.js",
26
+ "prepublishOnly": "node scripts/sync-version.js --check"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "engines": {
32
+ "node": ">=20"
33
+ },
34
+ "dependencies": {
35
+ "@iarna/toml": "^3.0.0"
36
+ },
37
+ "optionalDependencies": {
38
+ "fuigo-darwin-arm64": "1.0.2",
39
+ "fuigo-darwin-x64": "1.0.2",
40
+ "fuigo-linux-arm64": "1.0.2",
41
+ "fuigo-linux-x64": "1.0.2",
42
+ "fuigo-win32-arm64": "1.0.2",
43
+ "fuigo-win32-x64": "1.0.2"
44
+ }
21
45
  }
package/index.js DELETED
@@ -1,3 +0,0 @@
1
- // Fuigo — agent execution engine for Murage.
2
- // Placeholder while the implementation is in development.
3
- module.exports = { name: "fuigo", status: "in-development" };