@opennous/cli 0.2.0 → 0.4.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/package.json +3 -3
- package/src/index.js +71 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opennous/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Nous CLI — install Nous event tracking into your app, plus terminal access to the Context API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
"start": "node src/index.js"
|
|
13
13
|
},
|
|
14
14
|
"keywords": ["nous", "crm", "cli", "agents", "memory", "observability", "stripe"],
|
|
15
|
-
"license": "AGPL-3.0",
|
|
15
|
+
"license": "AGPL-3.0-only",
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
|
-
"url": "https://github.com/
|
|
18
|
+
"url": "https://github.com/NousC/nous.git",
|
|
19
19
|
"directory": "apps/cli"
|
|
20
20
|
},
|
|
21
21
|
"homepage": "https://opennous.cloud",
|
package/src/index.js
CHANGED
|
@@ -10,6 +10,17 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, appendFileSync } fr
|
|
|
10
10
|
import { homedir } from "os";
|
|
11
11
|
import { join, resolve } from "path";
|
|
12
12
|
import { createInterface } from "readline";
|
|
13
|
+
import { spawn } from "child_process";
|
|
14
|
+
|
|
15
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
16
|
+
|
|
17
|
+
// Best-effort open the user's browser; if it fails they have the printed URL.
|
|
18
|
+
function openBrowser(url) {
|
|
19
|
+
const cmd = process.platform === "darwin" ? "open"
|
|
20
|
+
: process.platform === "win32" ? "start"
|
|
21
|
+
: "xdg-open";
|
|
22
|
+
try { spawn(cmd, [url], { stdio: "ignore", detached: true }).unref(); } catch { /* printed URL is the fallback */ }
|
|
23
|
+
}
|
|
13
24
|
|
|
14
25
|
const CONFIG_PATH = join(homedir(), ".nous", "config.json");
|
|
15
26
|
|
|
@@ -648,4 +659,63 @@ program
|
|
|
648
659
|
});
|
|
649
660
|
|
|
650
661
|
// ---------------------------------------------------------------------------
|
|
651
|
-
|
|
662
|
+
// nous login — browser sign-in (device authorization). Opens the browser, you
|
|
663
|
+
// approve, and a freshly minted API key is saved to ~/.nous/config.json. No
|
|
664
|
+
// copy-paste. This is what the plugin's /nous-login command runs.
|
|
665
|
+
// ---------------------------------------------------------------------------
|
|
666
|
+
program
|
|
667
|
+
.command("login")
|
|
668
|
+
.description("Sign in with your browser and save an API key (no copy-paste)")
|
|
669
|
+
.option("--url <url>", "API base URL (default: https://api.opennous.cloud)")
|
|
670
|
+
.action(async ({ url }) => {
|
|
671
|
+
const apiUrl = url || process.env.NOUS_API_URL || readConfig().apiUrl || "https://api.opennous.cloud";
|
|
672
|
+
|
|
673
|
+
let start;
|
|
674
|
+
try {
|
|
675
|
+
const r = await fetch(`${apiUrl}/api/cli/auth/start`, {
|
|
676
|
+
method: "POST", headers: { "Content-Type": "application/json" }, body: "{}",
|
|
677
|
+
});
|
|
678
|
+
if (!r.ok) throw new Error(`server returned ${r.status}`);
|
|
679
|
+
start = await r.json();
|
|
680
|
+
} catch (e) {
|
|
681
|
+
console.error(`Couldn't start sign-in: ${e.message}`);
|
|
682
|
+
process.exit(1);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
console.log(`\nOpening your browser to authorize. If it doesn't open, visit:\n ${start.verification_uri_complete}\n`);
|
|
686
|
+
openBrowser(start.verification_uri_complete);
|
|
687
|
+
|
|
688
|
+
const interval = (start.interval || 4) * 1000;
|
|
689
|
+
const deadline = Date.now() + (start.expires_in || 600) * 1000;
|
|
690
|
+
process.stdout.write("Waiting for you to approve in the browser");
|
|
691
|
+
|
|
692
|
+
while (Date.now() < deadline) {
|
|
693
|
+
await sleep(interval);
|
|
694
|
+
process.stdout.write(".");
|
|
695
|
+
let j = {};
|
|
696
|
+
try {
|
|
697
|
+
const r = await fetch(`${apiUrl}/api/cli/auth/poll`, {
|
|
698
|
+
method: "POST", headers: { "Content-Type": "application/json" },
|
|
699
|
+
body: JSON.stringify({ device_code: start.device_code }),
|
|
700
|
+
});
|
|
701
|
+
j = await r.json().catch(() => ({}));
|
|
702
|
+
} catch { continue; }
|
|
703
|
+
|
|
704
|
+
if (j.status === "approved" && j.api_key) {
|
|
705
|
+
const cfg = readConfig();
|
|
706
|
+
cfg.apiKey = j.api_key;
|
|
707
|
+
cfg.apiUrl = apiUrl;
|
|
708
|
+
writeConfig(cfg);
|
|
709
|
+
console.log(`\n\n✓ Signed in. Key saved to ~/.nous/config.json`);
|
|
710
|
+
console.log("Your Nous tools are ready — try `get_workspace_status` in your agent.");
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
if (j.status === "denied") { console.log("\nAuthorization was denied."); process.exit(1); }
|
|
714
|
+
if (j.status === "expired") { console.log("\nThis sign-in expired. Run `nous login` again."); process.exit(1); }
|
|
715
|
+
}
|
|
716
|
+
console.log("\nTimed out waiting for approval. Run `nous login` again.");
|
|
717
|
+
process.exit(1);
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
// ---------------------------------------------------------------------------
|
|
721
|
+
program.name("nous").version("0.4.0").parse();
|