@meshxdata/fops 0.0.7 → 0.0.8
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/package.json +2 -4
- package/src/commands/index.js +31 -9
- package/src/plugins/skills.js +1 -1
- package/src/shell.js +7 -1
- package/src/ui/confirm.js +10 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meshxdata/fops",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "CLI to install and manage Foundation data mesh platforms",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"foundation",
|
|
@@ -25,9 +25,7 @@
|
|
|
25
25
|
"test:watch": "vitest"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"
|
|
29
|
-
"@anthropic-ai/claude-code": "^1.0.0",
|
|
30
|
-
"@meshxdata/fops": "0.0.6",
|
|
28
|
+
"@anthropic-ai/claude-code": "^2.1.39",
|
|
31
29
|
"boxen": "^8.0.1",
|
|
32
30
|
"chalk": "^5.3.0",
|
|
33
31
|
"commander": "^12.0.0",
|
package/src/commands/index.js
CHANGED
|
@@ -3,17 +3,9 @@ import os from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import https from "node:https";
|
|
5
5
|
import chalk from "chalk";
|
|
6
|
-
import { Command } from "commander";
|
|
7
6
|
import { PKG } from "../config.js";
|
|
8
7
|
import { rootDir, requireRoot, hasComposeInDir, isFoundationRoot, findComposeRootUp, checkInitState } from "../project.js";
|
|
9
|
-
import { execa } from "execa";
|
|
10
8
|
import { make, dockerCompose } from "../shell.js";
|
|
11
|
-
import { runSetup, runInitWizard } from "../setup/index.js";
|
|
12
|
-
import { ensureEcrAuth } from "../setup/aws.js";
|
|
13
|
-
import { runAgentSingleTurn, runAgentInteractive } from "../agent/index.js";
|
|
14
|
-
import { runDoctor } from "../doctor.js";
|
|
15
|
-
import { runFeatureFlags } from "../feature-flags.js";
|
|
16
|
-
import { runLogin, runCodaLogin } from "../auth/index.js";
|
|
17
9
|
import { runHook, loadSkills } from "../plugins/index.js";
|
|
18
10
|
|
|
19
11
|
export function registerCommands(program, registry) {
|
|
@@ -25,6 +17,7 @@ export function registerCommands(program, registry) {
|
|
|
25
17
|
.argument("[service]", "Service to login to: claude (default) or coda")
|
|
26
18
|
.option("--no-browser", "Paste API key in terminal instead of OAuth")
|
|
27
19
|
.action(async (service, opts) => {
|
|
20
|
+
const { runLogin, runCodaLogin } = await import("../auth/index.js");
|
|
28
21
|
const target = (service || "claude").toLowerCase();
|
|
29
22
|
if (target === "coda") {
|
|
30
23
|
await runCodaLogin();
|
|
@@ -46,6 +39,7 @@ export function registerCommands(program, registry) {
|
|
|
46
39
|
.option("--download", "Run make download after submodules", false)
|
|
47
40
|
.option("--yes", "Use defaults without prompting")
|
|
48
41
|
.action(async (opts) => {
|
|
42
|
+
const { runSetup } = await import("../setup/index.js");
|
|
49
43
|
const dir = opts.dir ? path.resolve(opts.dir) : (rootDir() || process.cwd());
|
|
50
44
|
if (!fs.existsSync(path.join(dir, "docker-compose.yaml")) && !fs.existsSync(path.join(dir, "docker-compose.yml"))) {
|
|
51
45
|
console.error(chalk.red("No docker-compose in %s. Run from foundation-compose root."), dir);
|
|
@@ -68,6 +62,7 @@ export function registerCommands(program, registry) {
|
|
|
68
62
|
.option("--no-submodules", "Skip git submodule init/update")
|
|
69
63
|
.option("--yes", "Use defaults without prompting; fail if no docker-compose in cwd")
|
|
70
64
|
.action(async (opts) => {
|
|
65
|
+
const { runSetup, runInitWizard } = await import("../setup/index.js");
|
|
71
66
|
const dir = opts.dir ? path.resolve(opts.dir) : process.cwd();
|
|
72
67
|
const hasCompose = hasComposeInDir(dir);
|
|
73
68
|
if (opts.yes) {
|
|
@@ -92,6 +87,7 @@ export function registerCommands(program, registry) {
|
|
|
92
87
|
.option("--no-run", "Do not offer to run suggested commands (single-turn only)", false)
|
|
93
88
|
.option("--model <id>", "Model override (e.g. claude-sonnet-4-20250514, gpt-4o-mini)")
|
|
94
89
|
.action(async (opts) => {
|
|
90
|
+
const { runAgentSingleTurn, runAgentInteractive } = await import("../agent/index.js");
|
|
95
91
|
const root = requireRoot(program);
|
|
96
92
|
if (opts.message) {
|
|
97
93
|
await runAgentSingleTurn(root, opts.message, { runSuggestions: opts.run !== false, model: opts.model, registry });
|
|
@@ -106,6 +102,8 @@ export function registerCommands(program, registry) {
|
|
|
106
102
|
.option("-d, --detach", "Run in background", true)
|
|
107
103
|
.option("--no-chat", "Skip interactive AI assistant after startup")
|
|
108
104
|
.action(async (opts) => {
|
|
105
|
+
const { execa } = await import("execa");
|
|
106
|
+
const { ensureEcrAuth } = await import("../setup/aws.js");
|
|
109
107
|
const root = requireRoot(program);
|
|
110
108
|
|
|
111
109
|
// Pre-flight: check if project is initialised
|
|
@@ -116,6 +114,19 @@ export function registerCommands(program, registry) {
|
|
|
116
114
|
process.exit(1);
|
|
117
115
|
}
|
|
118
116
|
|
|
117
|
+
// Pre-flight: check Docker daemon is reachable
|
|
118
|
+
try {
|
|
119
|
+
await execa("docker", ["info"], { timeout: 10000, reject: true });
|
|
120
|
+
} catch {
|
|
121
|
+
console.error(chalk.red("\n Docker daemon is not running or not reachable."));
|
|
122
|
+
if (process.platform === "linux") {
|
|
123
|
+
console.error(chalk.dim(" Try: sudo service docker start"));
|
|
124
|
+
} else {
|
|
125
|
+
console.error(chalk.dim(" Start Docker Desktop and try again."));
|
|
126
|
+
}
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
|
|
119
130
|
await ensureEcrAuth(root);
|
|
120
131
|
await runHook(registry, "before:up", { root });
|
|
121
132
|
|
|
@@ -152,16 +163,21 @@ export function registerCommands(program, registry) {
|
|
|
152
163
|
if (result.exitCode !== 0) {
|
|
153
164
|
console.error(chalk.red(`\n Some services failed to start (exit code ${result.exitCode}).`));
|
|
154
165
|
console.error(chalk.dim(" Dropping into debug agent to diagnose...\n"));
|
|
166
|
+
const { runAgentInteractive } = await import("../agent/index.js");
|
|
155
167
|
await runAgentInteractive(root, { registry, initialAgent: "debug" });
|
|
156
168
|
return;
|
|
157
169
|
}
|
|
158
|
-
if (opts.chat !== false)
|
|
170
|
+
if (opts.chat !== false) {
|
|
171
|
+
const { runAgentInteractive } = await import("../agent/index.js");
|
|
172
|
+
await runAgentInteractive(root, { registry });
|
|
173
|
+
}
|
|
159
174
|
});
|
|
160
175
|
|
|
161
176
|
program
|
|
162
177
|
.command("chat")
|
|
163
178
|
.description("Interactive AI assistant (same as foundation agent with no -m)")
|
|
164
179
|
.action(async () => {
|
|
180
|
+
const { runAgentInteractive } = await import("../agent/index.js");
|
|
165
181
|
const root = requireRoot(program);
|
|
166
182
|
await runAgentInteractive(root, { registry });
|
|
167
183
|
});
|
|
@@ -201,6 +217,7 @@ export function registerCommands(program, registry) {
|
|
|
201
217
|
.description("Check environment and Foundation setup (Docker, git, .env, submodules)")
|
|
202
218
|
.option("--fix", "Apply suggested fixes where possible", false)
|
|
203
219
|
.action(async (opts) => {
|
|
220
|
+
const { runDoctor } = await import("../doctor.js");
|
|
204
221
|
await runDoctor(opts, registry);
|
|
205
222
|
});
|
|
206
223
|
|
|
@@ -208,6 +225,7 @@ export function registerCommands(program, registry) {
|
|
|
208
225
|
.command("config")
|
|
209
226
|
.description("Toggle MX_FF_* feature flags and restart affected services")
|
|
210
227
|
.action(async () => {
|
|
228
|
+
const { runFeatureFlags } = await import("../feature-flags.js");
|
|
211
229
|
const root = requireRoot(program);
|
|
212
230
|
await runFeatureFlags(root);
|
|
213
231
|
});
|
|
@@ -216,6 +234,7 @@ export function registerCommands(program, registry) {
|
|
|
216
234
|
.command("build")
|
|
217
235
|
.description("Build all Foundation service images from source")
|
|
218
236
|
.action(async () => {
|
|
237
|
+
const { ensureEcrAuth } = await import("../setup/aws.js");
|
|
219
238
|
const root = requireRoot(program);
|
|
220
239
|
await ensureEcrAuth(root);
|
|
221
240
|
await make(root, "build");
|
|
@@ -225,6 +244,7 @@ export function registerCommands(program, registry) {
|
|
|
225
244
|
.command("download")
|
|
226
245
|
.description("Pull all container images from registry (requires ECR auth)")
|
|
227
246
|
.action(async () => {
|
|
247
|
+
const { ensureEcrAuth } = await import("../setup/aws.js");
|
|
228
248
|
const root = requireRoot(program);
|
|
229
249
|
await ensureEcrAuth(root);
|
|
230
250
|
await make(root, "download");
|
|
@@ -235,6 +255,7 @@ export function registerCommands(program, registry) {
|
|
|
235
255
|
.description("Update fops CLI to the latest version")
|
|
236
256
|
.option("--check", "Only check for updates, don't install")
|
|
237
257
|
.action(async (opts) => {
|
|
258
|
+
const { execa } = await import("execa");
|
|
238
259
|
const currentVersion = PKG.version;
|
|
239
260
|
console.log(chalk.dim(` Current version: ${currentVersion}`));
|
|
240
261
|
|
|
@@ -439,6 +460,7 @@ export function registerCommands(program, registry) {
|
|
|
439
460
|
.command("add <repo>")
|
|
440
461
|
.description("Install a plugin from GitHub (owner/repo)")
|
|
441
462
|
.action(async (repo) => {
|
|
463
|
+
const { execa } = await import("execa");
|
|
442
464
|
const parts = repo.split("/");
|
|
443
465
|
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
444
466
|
console.error(chalk.red(' Usage: fops plugin marketplace add <owner/repo>'));
|
package/src/plugins/skills.js
CHANGED
|
@@ -2,7 +2,6 @@ import fs from "node:fs";
|
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { execa } from "execa";
|
|
6
5
|
|
|
7
6
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
7
|
|
|
@@ -27,6 +26,7 @@ function parseFrontmatter(content) {
|
|
|
27
26
|
*/
|
|
28
27
|
async function hasBin(name) {
|
|
29
28
|
try {
|
|
29
|
+
const { execa } = await import("execa");
|
|
30
30
|
await execa("which", [name], { reject: false, timeout: 2000 });
|
|
31
31
|
return true;
|
|
32
32
|
} catch {
|
package/src/shell.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
let _execa;
|
|
2
|
+
async function lazyExeca() {
|
|
3
|
+
if (!_execa) _execa = (await import("execa")).execa;
|
|
4
|
+
return _execa;
|
|
5
|
+
}
|
|
2
6
|
|
|
3
7
|
export async function make(root, target, args = []) {
|
|
8
|
+
const execa = await lazyExeca();
|
|
4
9
|
return execa("make", [target, ...args], { cwd: root, stdio: "inherit", reject: false });
|
|
5
10
|
}
|
|
6
11
|
|
|
7
12
|
export async function dockerCompose(root, args) {
|
|
13
|
+
const execa = await lazyExeca();
|
|
8
14
|
return execa("docker", ["compose", ...args], { cwd: root, stdio: "inherit", reject: false });
|
|
9
15
|
}
|
package/src/ui/confirm.js
CHANGED
|
@@ -76,7 +76,16 @@ export async function selectOption(message, options) {
|
|
|
76
76
|
resolved = true;
|
|
77
77
|
clear();
|
|
78
78
|
unmount();
|
|
79
|
-
|
|
79
|
+
// Fix for Node 24+: restore stdin state after ink unmounts
|
|
80
|
+
// ink leaves stdin paused/in raw mode which breaks inquirer
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
if (process.stdin.isTTY) {
|
|
83
|
+
process.stdin.setRawMode(false);
|
|
84
|
+
process.stdin.resume();
|
|
85
|
+
process.stdin.ref();
|
|
86
|
+
}
|
|
87
|
+
resolve(selected ? selected.value : null);
|
|
88
|
+
}, 100);
|
|
80
89
|
};
|
|
81
90
|
const { unmount, clear } = render(
|
|
82
91
|
h(SelectPrompt, { message, options: normalized, onResult })
|