@agentgrant.cash/cli 1.3.0 → 1.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/dist/cli/commands/onboard.js +119 -0
- package/dist/cli/index.js +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, appendFileSync, } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join, dirname } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { buildContext, emit, ui } from "../../lib/index.js";
|
|
7
|
+
/**
|
|
8
|
+
* `grant onboard` — one-step setup for a fresh agent.
|
|
9
|
+
*
|
|
10
|
+
* This is the command the hosted onboarding skill (`/skill.md`) tells an agent
|
|
11
|
+
* to run after a user pastes "Set up https://<host>/skill.md". It:
|
|
12
|
+
* 1. installs the FULL Grant Cash skill (bundled in this package) into
|
|
13
|
+
* whatever coding agent it detects (Claude Code / Cursor / Codex /
|
|
14
|
+
* Windsurf / Continue), so the agent gains the complete command map, and
|
|
15
|
+
* 2. connects the account by running the real `login` flow, which prints the
|
|
16
|
+
* sign-in link and waits for the user to approve.
|
|
17
|
+
*
|
|
18
|
+
* Net effect: the agent goes from "knows nothing" to "skill installed + link
|
|
19
|
+
* in front of the user" from a single command, with no `curl | sh`.
|
|
20
|
+
*/
|
|
21
|
+
const SKILL_NAME = "grant-cash";
|
|
22
|
+
/** The full operational skill shipped inside this package. */
|
|
23
|
+
function readBundledSkill() {
|
|
24
|
+
const p = fileURLToPath(new URL("../../../skills/grant-cash/SKILL.md", import.meta.url));
|
|
25
|
+
return readFileSync(p, "utf8");
|
|
26
|
+
}
|
|
27
|
+
/** Detect installed agents and write the skill into each one's convention. */
|
|
28
|
+
function installSkill(skill) {
|
|
29
|
+
const home = homedir();
|
|
30
|
+
const installed = [];
|
|
31
|
+
const has = (rel) => existsSync(join(home, rel));
|
|
32
|
+
const writeFresh = (file) => {
|
|
33
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
34
|
+
writeFileSync(file, skill);
|
|
35
|
+
};
|
|
36
|
+
if (has(".claude")) {
|
|
37
|
+
const file = join(home, ".claude", "skills", SKILL_NAME, "SKILL.md");
|
|
38
|
+
writeFresh(file);
|
|
39
|
+
installed.push({ agent: "Claude Code", path: file });
|
|
40
|
+
}
|
|
41
|
+
if (has(".cursor")) {
|
|
42
|
+
const file = join(home, ".cursor", "rules", `${SKILL_NAME}.mdc`);
|
|
43
|
+
writeFresh(file);
|
|
44
|
+
installed.push({ agent: "Cursor", path: file });
|
|
45
|
+
}
|
|
46
|
+
if (has(".codex")) {
|
|
47
|
+
// Codex reads one AGENTS.md — append (deduped) rather than overwrite.
|
|
48
|
+
const file = join(home, ".codex", "AGENTS.md");
|
|
49
|
+
const existing = existsSync(file) ? readFileSync(file, "utf8") : "";
|
|
50
|
+
if (!/^name: grant-cash$/m.test(existing)) {
|
|
51
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
52
|
+
appendFileSync(file, (existing.trim() ? "\n\n---\n\n" : "") + skill);
|
|
53
|
+
}
|
|
54
|
+
installed.push({ agent: "Codex", path: file });
|
|
55
|
+
}
|
|
56
|
+
if (has(join(".codeium", "windsurf"))) {
|
|
57
|
+
const file = join(home, ".codeium", "windsurf", "memories", `${SKILL_NAME}.md`);
|
|
58
|
+
writeFresh(file);
|
|
59
|
+
installed.push({ agent: "Windsurf", path: file });
|
|
60
|
+
}
|
|
61
|
+
if (has(".continue")) {
|
|
62
|
+
const file = join(home, ".continue", "rules", `${SKILL_NAME}.md`);
|
|
63
|
+
writeFresh(file);
|
|
64
|
+
installed.push({ agent: "Continue", path: file });
|
|
65
|
+
}
|
|
66
|
+
// No known agent detected → default to the Claude Code layout so the skill
|
|
67
|
+
// still lands somewhere sane.
|
|
68
|
+
if (installed.length === 0) {
|
|
69
|
+
const file = join(home, ".claude", "skills", SKILL_NAME, "SKILL.md");
|
|
70
|
+
writeFresh(file);
|
|
71
|
+
installed.push({ agent: "Claude Code", path: file });
|
|
72
|
+
}
|
|
73
|
+
return installed;
|
|
74
|
+
}
|
|
75
|
+
export function registerOnboard(program) {
|
|
76
|
+
program
|
|
77
|
+
.command("onboard")
|
|
78
|
+
.description("Set up Grant Cash: install the skill into your agent and connect (one step)")
|
|
79
|
+
.option("--no-open", "do not auto-open the browser during sign-in; just print the link")
|
|
80
|
+
.option("--no-login", "only install the skill; skip sign-in")
|
|
81
|
+
.option("--timeout <seconds>", "how long to wait for the browser", "300")
|
|
82
|
+
.action(async (opts, cmd) => {
|
|
83
|
+
const ctx = buildContext(cmd);
|
|
84
|
+
const installed = installSkill(readBundledSkill());
|
|
85
|
+
if (!ctx.json) {
|
|
86
|
+
process.stdout.write(`\n${ui.title("Grant Cash — set up")}\n` +
|
|
87
|
+
installed
|
|
88
|
+
.map((t) => ` ${ui.green("✓")} ${t.agent.padEnd(12)} ${ui.dim(t.path)}`)
|
|
89
|
+
.join("\n") +
|
|
90
|
+
"\n");
|
|
91
|
+
}
|
|
92
|
+
// Install-only mode (e.g. CI, or re-installing the skill).
|
|
93
|
+
if (opts.login === false) {
|
|
94
|
+
emit(ctx, { installed, connected: false }, () => `\n${ui.green("✓ Skill installed.")} ${ui.dim("Run `grant login` to connect.")}\n`);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// Connect by re-running the real `login` command with inherited stdio, so
|
|
98
|
+
// the sign-in link prints, the browser opens, and polling completes
|
|
99
|
+
// exactly as `grant login` would. Forward the relevant flags.
|
|
100
|
+
const passthrough = ["login"];
|
|
101
|
+
if (ctx.json)
|
|
102
|
+
passthrough.push("--json");
|
|
103
|
+
if (opts.open === false)
|
|
104
|
+
passthrough.push("--no-open");
|
|
105
|
+
if (opts.timeout)
|
|
106
|
+
passthrough.push("--timeout", String(opts.timeout));
|
|
107
|
+
const globals = cmd.optsWithGlobals();
|
|
108
|
+
if (globals.credsFile)
|
|
109
|
+
passthrough.push("--creds-file", globals.credsFile);
|
|
110
|
+
if (!ctx.json) {
|
|
111
|
+
process.stdout.write(`\n${ui.dim("Connecting your account…")}\n`);
|
|
112
|
+
}
|
|
113
|
+
const res = spawnSync(process.execPath, [process.argv[1], ...passthrough], {
|
|
114
|
+
stdio: "inherit",
|
|
115
|
+
});
|
|
116
|
+
if (res.status && res.status !== 0)
|
|
117
|
+
process.exitCode = res.status;
|
|
118
|
+
});
|
|
119
|
+
}
|
package/dist/cli/index.js
CHANGED
|
@@ -25,6 +25,7 @@ import { registerPortfolio } from "./commands/portfolio.js";
|
|
|
25
25
|
import { registerMoney } from "./commands/money.js";
|
|
26
26
|
import { registerAgent } from "./commands/agent.js";
|
|
27
27
|
import { registerMeta } from "./commands/meta.js";
|
|
28
|
+
import { registerOnboard } from "./commands/onboard.js";
|
|
28
29
|
// ── full investing surface ported from the standalone Perfolio CLI ──
|
|
29
30
|
import { registerTrade } from "./perfolio-commands/trade.js";
|
|
30
31
|
import { registerMarket } from "./perfolio-commands/market.js";
|
|
@@ -55,6 +56,7 @@ program
|
|
|
55
56
|
.option("--json", "machine-readable JSON output")
|
|
56
57
|
.option("--creds-file <path>", "override ~/.grant-cash/credentials.json");
|
|
57
58
|
registerAuth(program);
|
|
59
|
+
registerOnboard(program);
|
|
58
60
|
registerPortfolio(program);
|
|
59
61
|
registerMoney(program);
|
|
60
62
|
registerAgent(program);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentgrant.cash/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Grant Cash — one CLI for your money (gold) and your agent (pay-per-use services). Routes to the Perfolio backend and the Agent-mode backend behind a single, plain-language surface.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|