@sammydev/justask 1.3.6

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/commands/me.js ADDED
@@ -0,0 +1,26 @@
1
+ const { apiGet } = require("../lib/api");
2
+
3
+ // --------------------
4
+ // ME [ node index.js me ]
5
+ // --------------------
6
+
7
+
8
+ module.exports = function (program) {
9
+ program
10
+ .command("whoami")
11
+ .description("Show authenticated CLI user")
12
+ .action(async () => {
13
+ try {
14
+ console.log("šŸ‘¤ Fetching user...\n");
15
+
16
+ const res = await apiGet("/api/cli/me");
17
+
18
+ console.log("āœ… User info:");
19
+ console.log(res.data);
20
+
21
+ } catch (err) {
22
+ console.log("āŒ Failed to fetch user");
23
+ console.log(err.response?.data || err.message);
24
+ }
25
+ });
26
+ };
@@ -0,0 +1,27 @@
1
+ const { apiGet } = require("../lib/api");
2
+
3
+ // --------------------
4
+ // PNG [ node index.js ping ]
5
+ // --------------------
6
+
7
+
8
+ module.exports = function (program) {
9
+ program
10
+ .command("ping")
11
+ .description("Test authenticated connection")
12
+ .action(async () => {
13
+ try {
14
+ const res = await apiGet("/api/cli/ping");
15
+
16
+ console.log("āœ… Server response:");
17
+ console.log(res.data);
18
+
19
+ } catch (err) {
20
+ console.log("āŒ Request failed");
21
+ console.log(
22
+ err.response?.data ||
23
+ err.message
24
+ );
25
+ }
26
+ });
27
+ };
@@ -0,0 +1,25 @@
1
+ const fs = require("fs-extra");
2
+ const path = require("path");
3
+
4
+ module.exports = function (program) {
5
+ program
6
+ .command("plugins")
7
+ .description("List installed plugins")
8
+ .action(() => {
9
+
10
+ const dir = path.join(process.cwd(), "plugins");
11
+
12
+ if (!fs.existsSync(dir)) {
13
+ console.log("No plugins installed");
14
+ return;
15
+ }
16
+
17
+ const files = fs.readdirSync(dir);
18
+
19
+ console.log("\nšŸ“¦ Installed plugins:\n");
20
+
21
+ files.forEach(file => {
22
+ console.log("- " + file.replace(".js", ""));
23
+ });
24
+ });
25
+ };
@@ -0,0 +1,34 @@
1
+ const { apiGet } = require("../lib/api");
2
+ const { saveConfig, getConfig } = require("../lib/config");
3
+
4
+ module.exports = function (program) {
5
+ program
6
+ .command("projects")
7
+ .description("List your projects")
8
+ .action(async () => {
9
+
10
+ try {
11
+ console.log("šŸ“¦ Loading projects...\n");
12
+
13
+ const res = await apiGet("/api/cli/projects");
14
+
15
+ const projects = res.data;
16
+
17
+ // SAVE LOCALLY (IMPORTANT FOR AUTO DETECTION LATER)
18
+ const config = getConfig();
19
+
20
+ saveConfig({
21
+ ...config,
22
+ projects
23
+ });
24
+
25
+ projects.forEach((p, i) => {
26
+ console.log(`${i + 1}. ${p.name} (${p.slug}) [ID: ${p.id}]`);
27
+ });
28
+
29
+ } catch (err) {
30
+ console.log("āŒ Failed to load projects");
31
+ console.log(err.response?.data || err.message);
32
+ }
33
+ });
34
+ };
@@ -0,0 +1,24 @@
1
+ const { apiPost } = require("../lib/api");
2
+
3
+ module.exports = function (program) {
4
+ program
5
+ .command("promote <id>")
6
+ .description("Promote deployment to production")
7
+ .action(async (id) => {
8
+
9
+ try {
10
+ console.log(`šŸš€ Promoting deployment ${id}...`);
11
+
12
+ const res = await apiPost("/api/cli/deployments/promote", {
13
+ deployment_id: id
14
+ });
15
+
16
+ console.log("āœ… Promoted successfully");
17
+ console.log(res.data);
18
+
19
+ } catch (err) {
20
+ console.log("āŒ Promote failed");
21
+ console.log(err.response?.data || err.message);
22
+ }
23
+ });
24
+ };
@@ -0,0 +1,24 @@
1
+ const { apiPost } = require("../lib/api");
2
+
3
+ module.exports = function (program) {
4
+ program
5
+ .command("rollback <id>")
6
+ .description("Rollback a deployment")
7
+ .action(async (id) => {
8
+
9
+ try {
10
+ console.log("šŸ”„ Rolling back deployment:", id);
11
+
12
+ const res = await apiPost("/api/cli/rollback", {
13
+ deployment_id: id
14
+ });
15
+
16
+ console.log("āœ… Rollback complete");
17
+ console.log(res.data);
18
+
19
+ } catch (err) {
20
+ console.log("āŒ Rollback failed");
21
+ console.log(err.response?.data || err.message);
22
+ }
23
+ });
24
+ };
@@ -0,0 +1,56 @@
1
+ const path = require("path");
2
+ const fs = require("fs-extra");
3
+ const { getConfig } = require("../lib/config");
4
+
5
+ module.exports = function (program) {
6
+ program
7
+ .command("run <plugin> [args...]")
8
+ .description("Run an installed plugin")
9
+ .action(async (plugin, args) => {
10
+
11
+ try {
12
+ const config = getConfig();
13
+
14
+ const pluginPath = path.join(
15
+ process.cwd(),
16
+ "plugins",
17
+ `${plugin}.js`
18
+ );
19
+
20
+ if (!fs.existsSync(pluginPath)) {
21
+ console.log(`āŒ Plugin "${plugin}" not found`);
22
+ return;
23
+ }
24
+
25
+ console.log(`šŸš€ Running plugin: ${plugin}`);
26
+
27
+ // clear cache so updates work instantly
28
+ delete require.cache[require.resolve(pluginPath)];
29
+
30
+ const mod = require(pluginPath);
31
+
32
+ if (!mod || typeof mod.run !== "function") {
33
+ console.log("āŒ Plugin must export a run() function");
34
+ return;
35
+ }
36
+
37
+ // --------------------
38
+ // CONTEXT OBJECT (IMPORTANT)
39
+ // --------------------
40
+ const context = {
41
+ config,
42
+ cwd: process.cwd(),
43
+ env: process.env
44
+ };
45
+
46
+ // --------------------
47
+ // EXECUTE PLUGIN
48
+ // --------------------
49
+ await mod.run(args, context);
50
+
51
+ } catch (err) {
52
+ console.log("āŒ Failed to run plugin");
53
+ console.log(err.message);
54
+ }
55
+ });
56
+ };
@@ -0,0 +1,37 @@
1
+ const { apiGet } = require("../lib/api");
2
+
3
+ module.exports = function (program) {
4
+ program
5
+ .command("search <type> <query>")
6
+ .description("Search plugins or packages")
7
+ .action(async (type, query) => {
8
+
9
+ if (type !== "plugin") {
10
+ console.log("āŒ Only plugin search supported");
11
+ return;
12
+ }
13
+
14
+ try {
15
+ const res = await apiGet(`/api/cli/plugins/search?q=${query}`);
16
+
17
+ const plugins = res.data;
18
+
19
+ if (!plugins.length) {
20
+ console.log("No plugins found");
21
+ return;
22
+ }
23
+
24
+ console.log("\nšŸ”Ž Plugins found:\n");
25
+
26
+ plugins.forEach((p, i) => {
27
+ console.log(`${i + 1}. ${p.name}`);
28
+ console.log(` ${p.description}`);
29
+ console.log(` repo: ${p.repo}\n`);
30
+ });
31
+
32
+ } catch (err) {
33
+ console.log("āŒ Search failed");
34
+ console.log(err.response?.data || err.message);
35
+ }
36
+ });
37
+ };
@@ -0,0 +1,33 @@
1
+ const { apiGet } = require("../lib/api");
2
+
3
+ module.exports = function (program) {
4
+ program
5
+ .command("status")
6
+ .description("Show latest deployment status")
7
+ .action(async () => {
8
+
9
+ try {
10
+ console.log("šŸ“Š Fetching deployment status...\n");
11
+
12
+ const res = await apiGet("/api/cli/deployments/status");
13
+
14
+ const d = res.data.latest;
15
+
16
+ if (!d) {
17
+ console.log("No deployments yet");
18
+ return;
19
+ }
20
+
21
+ console.log("šŸ”„ Latest Deployment:");
22
+ console.log(`ID: ${d.id}`);
23
+ console.log(`Project: ${d.project_id}`);
24
+ console.log(`Env: ${d.env}`);
25
+ console.log(`Status: ${d.status}`);
26
+ console.log(`Version: ${d.version}`);
27
+
28
+ } catch (err) {
29
+ console.log("āŒ Failed to fetch status");
30
+ console.log(err.response?.data || err.message);
31
+ }
32
+ });
33
+ };
@@ -0,0 +1,22 @@
1
+ const { getConfig, saveConfig } = require("../lib/config");
2
+
3
+ module.exports = function (program) {
4
+ program
5
+ .command("use <id>")
6
+ .description("Select active project")
7
+ .action((id) => {
8
+
9
+ const config = getConfig();
10
+
11
+ const project = config.projects?.find
12
+ ? config.projects.find(p => p.id == id)
13
+ : null;
14
+
15
+ saveConfig({
16
+ ...config,
17
+ active_project: id
18
+ });
19
+
20
+ console.log(`āœ… Active project set to ID: ${id}`);
21
+ });
22
+ };
package/index.js ADDED
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { program } = require("commander");
4
+ const { getConfig } = require("./lib/config");
5
+ const { loadCommands } = require("./lib/loadCommands");
6
+
7
+ // --------------------
8
+ // CLI SETUP
9
+ // --------------------
10
+
11
+ program
12
+ .name("justask")
13
+ .description("Developer CLI for managing your Laravel projects")
14
+ .version("1.0.0")
15
+ .addHelpText(
16
+ "after",
17
+ `
18
+ Examples:
19
+ justask login
20
+ justask init
21
+ justask deploy
22
+ justask status
23
+ justask history
24
+ justask install plugin github:user/plugin-slack
25
+ `
26
+ );
27
+
28
+ // --------------------
29
+ // SHORTCUTS (SAFE - NO RELOADING COMMANDS)
30
+ // --------------------
31
+
32
+ function run(cmd) {
33
+ program.parse(["node", "justask", cmd]);
34
+ }
35
+
36
+ program
37
+ .command("d")
38
+ .description("Shortcut for deploy")
39
+ .action(() => run("deploy"));
40
+
41
+ program
42
+ .command("st")
43
+ .description("Shortcut for status")
44
+ .action(() => run("status"));
45
+
46
+ program
47
+ .command("h")
48
+ .description("Shortcut for history")
49
+ .action(() => run("history"));
50
+
51
+ // --------------------
52
+ // LOAD ALL COMMANDS (ONLY ONCE)
53
+ // --------------------
54
+
55
+ // IMPORTANT: loadCommands must internally prevent double-loading
56
+ loadCommands(program);
57
+
58
+ // --------------------
59
+ // UNKNOWN COMMAND HANDLER
60
+ // --------------------
61
+
62
+ program.on("command:*", function () {
63
+ console.log("\nāŒ Unknown command");
64
+ console.log("šŸ‘‰ Try:");
65
+ console.log(" justask deploy");
66
+ console.log(" justask status");
67
+ console.log(" justask history");
68
+ console.log(" justask init\n");
69
+ });
70
+
71
+ // --------------------
72
+ // FIRST RUN UX
73
+ // --------------------
74
+
75
+ const config = getConfig();
76
+
77
+ if (!config._hasRun) {
78
+ console.log("\nšŸ‘‹ Welcome to Justask CLI");
79
+ console.log("šŸš€ Quick start:");
80
+ console.log(" justask init");
81
+ console.log(" justask deploy\n");
82
+ }
83
+
84
+ // --------------------
85
+ // RUN CLI
86
+ // --------------------
87
+
88
+ program.parse();
package/justalk.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "project_id": 1,
3
+ "project_slug": "cli-project-1"
4
+ }
package/lib/api.js ADDED
@@ -0,0 +1,42 @@
1
+ const axios = require("axios");
2
+ const { getConfig } = require("./config");
3
+
4
+ const API_BASE = "http://127.0.0.1:8000";
5
+
6
+ /**
7
+ * Always use API key for CLI requests
8
+ */
9
+ function getAuthHeaders() {
10
+ const config = getConfig();
11
+
12
+ if (!config.api_key) {
13
+ return {};
14
+ }
15
+
16
+ return {
17
+ "X-API-KEY": config.api_key
18
+ };
19
+ }
20
+
21
+ /**
22
+ * GET request
23
+ */
24
+ function apiGet(path) {
25
+ return axios.get(`${API_BASE}${path}`, {
26
+ headers: getAuthHeaders()
27
+ });
28
+ }
29
+
30
+ /**
31
+ * POST request
32
+ */
33
+ function apiPost(path, data = {}) {
34
+ return axios.post(`${API_BASE}${path}`, data, {
35
+ headers: getAuthHeaders()
36
+ });
37
+ }
38
+
39
+ module.exports = {
40
+ apiGet,
41
+ apiPost
42
+ };
package/lib/config.js ADDED
@@ -0,0 +1,62 @@
1
+ const fs = require("fs-extra");
2
+
3
+ const CONFIG_PATH = "./config.json";
4
+
5
+ /**
6
+ * Load config safely
7
+ */
8
+ function getConfig() {
9
+ try {
10
+ if (!fs.existsSync(CONFIG_PATH)) return {};
11
+ return fs.readJSONSync(CONFIG_PATH);
12
+ } catch (e) {
13
+ return {};
14
+ }
15
+ }
16
+
17
+ /**
18
+ * Save config safely (merge-safe)
19
+ */
20
+ function saveConfig(data) {
21
+ const current = getConfig();
22
+
23
+ const merged = {
24
+ ...current,
25
+ ...data
26
+ };
27
+
28
+ fs.writeJSONSync(CONFIG_PATH, merged, { spaces: 2 });
29
+ }
30
+
31
+ /**
32
+ * Get active project
33
+ */
34
+ function getActiveProject() {
35
+ const config = getConfig();
36
+ return config.active_project || null;
37
+ }
38
+
39
+ /**
40
+ * Get environment (dev/prod)
41
+ */
42
+ function getEnv() {
43
+ const config = getConfig();
44
+ return config.env || "prod";
45
+ }
46
+
47
+ function isFirstRun() {
48
+ const config = getConfig();
49
+ return !config._hasRun;
50
+ saveConfig({
51
+ ...config,
52
+ _hasRun: true
53
+ });
54
+ }
55
+
56
+ module.exports = {
57
+ getConfig,
58
+ saveConfig,
59
+ getActiveProject,
60
+ getEnv,
61
+ isFirstRun
62
+ };
@@ -0,0 +1,23 @@
1
+ const { execSync } = require("child_process");
2
+
3
+ function getCurrentBranch() {
4
+ try {
5
+ const branch = execSync(
6
+ "git rev-parse --abbrev-ref HEAD 2>/dev/null"
7
+ )
8
+ .toString()
9
+ .trim();
10
+
11
+ if (!branch || branch === "HEAD") {
12
+ return null;
13
+ }
14
+
15
+ return branch;
16
+ } catch (e) {
17
+ return null;
18
+ }
19
+ }
20
+
21
+ module.exports = {
22
+ getCurrentBranch
23
+ };
@@ -0,0 +1,46 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ let loaded = false;
5
+
6
+ function loadCommands(program) {
7
+
8
+ // --------------------
9
+ // PREVENT DOUBLE LOAD
10
+ // --------------------
11
+ if (loaded) return;
12
+ loaded = true;
13
+
14
+ const commandsPath = path.join(__dirname, "../commands");
15
+
16
+ // --------------------
17
+ // LOAD CORE COMMANDS ONLY
18
+ // --------------------
19
+ if (fs.existsSync(commandsPath)) {
20
+ const commandFiles = fs.readdirSync(commandsPath)
21
+ .filter(file => file.endsWith(".js"));
22
+
23
+ for (const file of commandFiles) {
24
+
25
+ const commandPath = path.join(commandsPath, file);
26
+
27
+ // clear require cache safety (important for dev reloads)
28
+ delete require.cache[require.resolve(commandPath)];
29
+
30
+ const command = require(commandPath);
31
+
32
+ if (typeof command === "function") {
33
+ command(program);
34
+ }
35
+ }
36
+ }
37
+
38
+ // --------------------
39
+ // IMPORTANT CHANGE:
40
+ // DO NOT AUTO-LOAD PLUGINS
41
+ // --------------------
42
+ // Plugins are now executed ONLY via:
43
+ // justalk run <plugin>
44
+ }
45
+
46
+ module.exports = { loadCommands };
@@ -0,0 +1,16 @@
1
+ const fs = require("fs-extra");
2
+ const path = require("path");
3
+
4
+ function getLinkedProject() {
5
+ const file = path.join(process.cwd(), ".justalk.json");
6
+
7
+ if (fs.existsSync(file)) {
8
+ return fs.readJSONSync(file).project_id;
9
+ }
10
+
11
+ return null;
12
+ }
13
+
14
+ module.exports = {
15
+ getLinkedProject
16
+ };
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "@sammydev/justask",
3
+ "version": "1.3.6",
4
+ "bin": {
5
+ "justask": "./index.js"
6
+ },
7
+ "description": "Developer way of production friends",
8
+ "main": "index.js",
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ },
12
+ "keywords": [],
13
+ "author": "",
14
+ "license": "ISC",
15
+ "type": "commonjs",
16
+ "dependencies": {
17
+ "axios": "^1.16.1",
18
+ "commander": "^14.0.3",
19
+ "fs-extra": "^11.3.5"
20
+ }
21
+ }
@@ -0,0 +1,18 @@
1
+ // module.exports = {
2
+ // name: "slack",
3
+
4
+ // run: async (args, context) => {
5
+ // console.log("Slack plugin working!");
6
+ // console.log("Args:", args);
7
+ // }
8
+ // };
9
+
10
+ module.exports = {
11
+ name: "slack",
12
+
13
+ run: async (args, context) => {
14
+ console.log("Slack working!");
15
+ console.log("Args:", args);
16
+ console.log("Project:", context.config);
17
+ }
18
+ };
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "slack",
3
+ "version": "1.0.0",
4
+ "main": "index.js",
5
+ "author": "sammydev",
6
+ "description": "Slack notifications for Justalk",
7
+ "entry": "index.js"
8
+ }
@@ -0,0 +1,9 @@
1
+ module.exports = {
2
+ name: "slack",
3
+
4
+ run: async (args, context) => {
5
+ console.log("Slack working!");
6
+ console.log("Args:", args);
7
+ console.log("Project:", context.config);
8
+ }
9
+ };