codecard-cli 0.1.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/LICENSE +21 -0
- package/README.md +94 -0
- package/dist/commands/alerts.d.ts +2 -0
- package/dist/commands/alerts.js +44 -0
- package/dist/commands/auth/login.d.ts +2 -0
- package/dist/commands/auth/login.js +43 -0
- package/dist/commands/auth/logout.d.ts +2 -0
- package/dist/commands/auth/logout.js +20 -0
- package/dist/commands/auth/whoami.d.ts +2 -0
- package/dist/commands/auth/whoami.js +32 -0
- package/dist/commands/balance.d.ts +2 -0
- package/dist/commands/balance.js +35 -0
- package/dist/commands/card/freeze.d.ts +3 -0
- package/dist/commands/card/freeze.js +68 -0
- package/dist/commands/card/list.d.ts +2 -0
- package/dist/commands/card/list.js +44 -0
- package/dist/commands/pnl.d.ts +2 -0
- package/dist/commands/pnl.js +57 -0
- package/dist/commands/project/create.d.ts +2 -0
- package/dist/commands/project/create.js +36 -0
- package/dist/commands/project/list.d.ts +2 -0
- package/dist/commands/project/list.js +42 -0
- package/dist/commands/rewards.d.ts +2 -0
- package/dist/commands/rewards.js +61 -0
- package/dist/commands/spend.d.ts +2 -0
- package/dist/commands/spend.js +116 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +52 -0
- package/dist/lib/api-client.d.ts +23 -0
- package/dist/lib/api-client.js +113 -0
- package/dist/lib/config.d.ts +16 -0
- package/dist/lib/config.js +40 -0
- package/dist/lib/output.d.ts +20 -0
- package/dist/lib/output.js +69 -0
- package/dist/lib/update-check.d.ts +1 -0
- package/dist/lib/update-check.js +74 -0
- package/dist/mcp-server.d.ts +2 -0
- package/dist/mcp-server.js +133 -0
- package/dist/shared/alert.d.ts +24 -0
- package/dist/shared/alert.js +2 -0
- package/dist/shared/alerts.d.ts +3 -0
- package/dist/shared/alerts.js +103 -0
- package/dist/shared/card.d.ts +12 -0
- package/dist/shared/card.js +2 -0
- package/dist/shared/cards.d.ts +2 -0
- package/dist/shared/cards.js +60 -0
- package/dist/shared/common.d.ts +21 -0
- package/dist/shared/common.js +2 -0
- package/dist/shared/filters.d.ts +8 -0
- package/dist/shared/filters.js +59 -0
- package/dist/shared/formatters.d.ts +7 -0
- package/dist/shared/formatters.js +44 -0
- package/dist/shared/index.d.ts +15 -0
- package/dist/shared/index.js +43 -0
- package/dist/shared/project.d.ts +24 -0
- package/dist/shared/project.js +2 -0
- package/dist/shared/projects.d.ts +3 -0
- package/dist/shared/projects.js +104 -0
- package/dist/shared/reward.d.ts +26 -0
- package/dist/shared/reward.js +2 -0
- package/dist/shared/rewards.d.ts +4 -0
- package/dist/shared/rewards.js +25 -0
- package/dist/shared/transaction.d.ts +36 -0
- package/dist/shared/transaction.js +2 -0
- package/dist/shared/transactions.d.ts +2 -0
- package/dist/shared/transactions.js +34 -0
- package/dist/shared/user.d.ts +12 -0
- package/dist/shared/user.js +2 -0
- package/dist/shared/users.d.ts +3 -0
- package/dist/shared/users.js +15 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Code Financial, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# codecard-cli
|
|
2
|
+
|
|
3
|
+
> **code_** — The financial stack for AI-native builders
|
|
4
|
+
|
|
5
|
+
CLI tool for managing your Code_ neobank account. Track spend, manage virtual cards, view project P&L, earn rewards — all from the terminal.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g codecard-cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Authenticate
|
|
17
|
+
codecard auth login
|
|
18
|
+
|
|
19
|
+
# Create a project (auto-provisions a virtual Visa card)
|
|
20
|
+
codecard project create "my-ai-app" --budget 3000
|
|
21
|
+
|
|
22
|
+
# View your spend
|
|
23
|
+
codecard spend
|
|
24
|
+
|
|
25
|
+
# Check project P&L
|
|
26
|
+
codecard pnl my-ai-app
|
|
27
|
+
|
|
28
|
+
# See rewards earned
|
|
29
|
+
codecard rewards
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Commands
|
|
33
|
+
|
|
34
|
+
| Command | Description |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `codecard auth login` | Authenticate via browser OAuth or API key |
|
|
37
|
+
| `codecard auth logout` | Clear stored credentials |
|
|
38
|
+
| `codecard auth whoami` | Show current user |
|
|
39
|
+
| `codecard project list` | List all projects |
|
|
40
|
+
| `codecard project create <name>` | Create project + virtual card |
|
|
41
|
+
| `codecard spend` | View spend breakdown |
|
|
42
|
+
| `codecard balance` | Check balance and credit |
|
|
43
|
+
| `codecard pnl <project>` | Project profit & loss |
|
|
44
|
+
| `codecard card list` | List virtual cards |
|
|
45
|
+
| `codecard card freeze <id>` | Freeze a card |
|
|
46
|
+
| `codecard card unfreeze <id>` | Unfreeze a card |
|
|
47
|
+
| `codecard rewards` | View Code Credits |
|
|
48
|
+
| `codecard alerts` | View spend alerts |
|
|
49
|
+
| `codecard mcp` | Start MCP server for AI agents |
|
|
50
|
+
|
|
51
|
+
## JSON Output
|
|
52
|
+
|
|
53
|
+
Every command supports `--json` for machine-readable output:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
codecard balance --json | jq '.available'
|
|
57
|
+
# → 12400
|
|
58
|
+
|
|
59
|
+
codecard spend --json --project my-ai-app | jq '.byProvider'
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## MCP Server
|
|
63
|
+
|
|
64
|
+
The CLI includes a built-in MCP (Model Context Protocol) server, letting AI agents manage your finances:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Start the MCP server
|
|
68
|
+
codecard mcp
|
|
69
|
+
|
|
70
|
+
# Add to Claude Code
|
|
71
|
+
claude mcp add codecard -- codecard mcp
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Available tools:** `list_projects`, `create_project`, `get_project_pnl`, `get_spend`, `get_balance`, `list_cards`, `freeze_card`, `unfreeze_card`, `get_rewards`, `get_alerts`
|
|
75
|
+
|
|
76
|
+
## Reward Rates
|
|
77
|
+
|
|
78
|
+
| Category | Rate |
|
|
79
|
+
|---|---|
|
|
80
|
+
| AI Model APIs (OpenAI, Anthropic, etc.) | **5%** |
|
|
81
|
+
| Cloud & Infrastructure (Vercel, AWS, etc.) | **4%** |
|
|
82
|
+
| Dev Tools & SaaS (GitHub, Cursor, etc.) | **3%** |
|
|
83
|
+
| Everything Else | **1%** |
|
|
84
|
+
|
|
85
|
+
## Links
|
|
86
|
+
|
|
87
|
+
- **Website:** [codecard.ai](https://codecard.ai)
|
|
88
|
+
- **Dashboard:** [codecard.ai/dashboard](https://codecard.ai/dashboard)
|
|
89
|
+
- **Docs:** [codecard.ai/docs](https://codecard.ai/docs)
|
|
90
|
+
- **GitHub:** [github.com/rajparekh7/code_](https://github.com/rajparekh7/code_)
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
MIT
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.alertsCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const config_1 = require("../lib/config");
|
|
10
|
+
const api_client_1 = require("../lib/api-client");
|
|
11
|
+
const output_1 = require("../lib/output");
|
|
12
|
+
const severityColor = {
|
|
13
|
+
critical: output_1.pink,
|
|
14
|
+
warning: output_1.orange,
|
|
15
|
+
info: output_1.blue,
|
|
16
|
+
};
|
|
17
|
+
exports.alertsCommand = new commander_1.Command("alerts")
|
|
18
|
+
.description("View spend alerts")
|
|
19
|
+
.option("--json", "Output as JSON")
|
|
20
|
+
.action(async (opts) => {
|
|
21
|
+
if (!(0, config_1.isAuthenticated)()) {
|
|
22
|
+
(0, output_1.printError)("Not authenticated. Run " + (0, output_1.accent)("code auth login") + " first.");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const spinner = (0, ora_1.default)({ text: "Fetching alerts...", color: "green" }).start();
|
|
26
|
+
const { events } = await (0, api_client_1.getAlerts)();
|
|
27
|
+
spinner.stop();
|
|
28
|
+
if (opts.json) {
|
|
29
|
+
(0, output_1.printJson)(events);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const unacked = events.filter((e) => !e.acknowledged).length;
|
|
33
|
+
(0, output_1.printHeader)(`Alerts (${unacked} unread)`);
|
|
34
|
+
for (const event of events) {
|
|
35
|
+
const color = severityColor[event.severity] || output_1.muted;
|
|
36
|
+
const badge = event.acknowledged ? (0, output_1.dim)(" ○") : color(" ●");
|
|
37
|
+
const severity = color(event.severity.toUpperCase().padEnd(8));
|
|
38
|
+
console.log();
|
|
39
|
+
console.log(badge + " " + severity + " " + event.title);
|
|
40
|
+
console.log((0, output_1.dim)(" " + event.projectName + " · " + new Date(event.triggeredAt).toLocaleDateString()));
|
|
41
|
+
console.log((0, output_1.muted)(" " + event.message));
|
|
42
|
+
}
|
|
43
|
+
console.log();
|
|
44
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.loginCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const config_1 = require("../../lib/config");
|
|
10
|
+
const output_1 = require("../../lib/output");
|
|
11
|
+
exports.loginCommand = new commander_1.Command("login")
|
|
12
|
+
.description("Authenticate with Code_")
|
|
13
|
+
.option("--api-key <key>", "Authenticate with an API key")
|
|
14
|
+
.option("--json", "Output as JSON")
|
|
15
|
+
.action(async (opts) => {
|
|
16
|
+
if (opts.apiKey) {
|
|
17
|
+
(0, config_1.setAuth)("sarah@dev.io", "Sarah Chen", opts.apiKey);
|
|
18
|
+
if (opts.json) {
|
|
19
|
+
(0, output_1.printJson)({ success: true, email: "sarah@dev.io", name: "Sarah Chen" });
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
(0, output_1.printHeader)("Authentication");
|
|
23
|
+
(0, output_1.printSuccess)("Authenticated as " + (0, output_1.accent)("sarah@dev.io"));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (!opts.json) {
|
|
27
|
+
(0, output_1.printHeader)("Authentication");
|
|
28
|
+
console.log();
|
|
29
|
+
}
|
|
30
|
+
const spinner = (0, ora_1.default)({ text: "Opening browser for authentication...", color: "green" }).start();
|
|
31
|
+
await (0, output_1.delay)(1500);
|
|
32
|
+
spinner.text = "Waiting for browser confirmation...";
|
|
33
|
+
await (0, output_1.delay)(1000);
|
|
34
|
+
spinner.succeed("Browser authentication complete");
|
|
35
|
+
(0, config_1.setAuth)("sarah@dev.io", "Sarah Chen", "mock_token_abc123xyz");
|
|
36
|
+
if (opts.json) {
|
|
37
|
+
(0, output_1.printJson)({ success: true, email: "sarah@dev.io", name: "Sarah Chen" });
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
(0, output_1.printSuccess)("Authenticated as " + (0, output_1.accent)("sarah@dev.io"));
|
|
41
|
+
console.log();
|
|
42
|
+
}
|
|
43
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.logoutCommand = void 0;
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const config_1 = require("../../lib/config");
|
|
6
|
+
const output_1 = require("../../lib/output");
|
|
7
|
+
exports.logoutCommand = new commander_1.Command("logout")
|
|
8
|
+
.description("Log out of Code_")
|
|
9
|
+
.option("--json", "Output as JSON")
|
|
10
|
+
.action((opts) => {
|
|
11
|
+
(0, config_1.clearAuth)();
|
|
12
|
+
if (opts.json) {
|
|
13
|
+
(0, output_1.printJson)({ success: true, message: "Logged out" });
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
(0, output_1.printHeader)("Authentication");
|
|
17
|
+
(0, output_1.printSuccess)("Logged out successfully.");
|
|
18
|
+
console.log();
|
|
19
|
+
}
|
|
20
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.whoamiCommand = void 0;
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const config_1 = require("../../lib/config");
|
|
6
|
+
const output_1 = require("../../lib/output");
|
|
7
|
+
exports.whoamiCommand = new commander_1.Command("whoami")
|
|
8
|
+
.description("Show current authenticated user")
|
|
9
|
+
.option("--json", "Output as JSON")
|
|
10
|
+
.action((opts) => {
|
|
11
|
+
const auth = (0, config_1.getAuth)();
|
|
12
|
+
if (!auth) {
|
|
13
|
+
if (opts.json) {
|
|
14
|
+
(0, output_1.printJsonError)("Not authenticated");
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
(0, output_1.printHeader)("Who Am I");
|
|
18
|
+
(0, output_1.printError)("Not authenticated. Run " + (0, output_1.accent)("code auth login") + " first.");
|
|
19
|
+
console.log();
|
|
20
|
+
}
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (opts.json) {
|
|
24
|
+
(0, output_1.printJson)({ authenticated: true, email: auth.email, name: auth.name });
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
(0, output_1.printHeader)("Who Am I");
|
|
28
|
+
(0, output_1.printRow)("Name", auth.name);
|
|
29
|
+
(0, output_1.printRow)("Email", auth.email);
|
|
30
|
+
console.log();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.balanceCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const config_1 = require("../lib/config");
|
|
10
|
+
const api_client_1 = require("../lib/api-client");
|
|
11
|
+
const output_1 = require("../lib/output");
|
|
12
|
+
const shared_1 = require("../shared");
|
|
13
|
+
exports.balanceCommand = new commander_1.Command("balance")
|
|
14
|
+
.description("Check account balance and credit")
|
|
15
|
+
.option("--json", "Output as JSON")
|
|
16
|
+
.action(async (opts) => {
|
|
17
|
+
if (!(0, config_1.isAuthenticated)()) {
|
|
18
|
+
(0, output_1.printError)("Not authenticated. Run " + (0, output_1.accent)("code auth login") + " first.");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const spinner = (0, ora_1.default)({ text: "Fetching balance...", color: "green" }).start();
|
|
22
|
+
const bal = await (0, api_client_1.getBalance)();
|
|
23
|
+
spinner.stop();
|
|
24
|
+
if (opts.json) {
|
|
25
|
+
(0, output_1.printJson)(bal);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
(0, output_1.printHeader)("Account Balance");
|
|
29
|
+
(0, output_1.printRow)("Available", (0, shared_1.currency)(bal.available));
|
|
30
|
+
(0, output_1.printRow)("Pending", (0, shared_1.currency)(bal.pending));
|
|
31
|
+
(0, output_1.printRow)("Credit limit", (0, shared_1.currency)(bal.creditLimit));
|
|
32
|
+
(0, output_1.printRow)("Credit used", (0, shared_1.currency)(bal.creditUsed));
|
|
33
|
+
(0, output_1.printRow)("Credit available", (0, shared_1.currency)(bal.creditLimit - bal.creditUsed));
|
|
34
|
+
console.log();
|
|
35
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.cardUnfreezeCommand = exports.cardFreezeCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const config_1 = require("../../lib/config");
|
|
10
|
+
const api_client_1 = require("../../lib/api-client");
|
|
11
|
+
const output_1 = require("../../lib/output");
|
|
12
|
+
const shared_1 = require("../../shared");
|
|
13
|
+
exports.cardFreezeCommand = new commander_1.Command("freeze")
|
|
14
|
+
.description("Freeze a virtual card")
|
|
15
|
+
.argument("<cardId>", "Card ID to freeze")
|
|
16
|
+
.option("--json", "Output as JSON")
|
|
17
|
+
.action(async (cardId, opts) => {
|
|
18
|
+
if (!(0, config_1.isAuthenticated)()) {
|
|
19
|
+
(0, output_1.printError)("Not authenticated. Run " + (0, output_1.accent)("code auth login") + " first.");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const spinner = (0, ora_1.default)({ text: "Freezing card...", color: "green" }).start();
|
|
23
|
+
const card = await (0, api_client_1.freezeCard)(cardId);
|
|
24
|
+
spinner.stop();
|
|
25
|
+
if (!card) {
|
|
26
|
+
if (opts.json)
|
|
27
|
+
(0, output_1.printJsonError)("Card not found");
|
|
28
|
+
else
|
|
29
|
+
(0, output_1.printError)("Card " + cardId + " not found.");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (opts.json) {
|
|
33
|
+
(0, output_1.printJson)({ success: true, card });
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
(0, output_1.printHeader)("Card Frozen");
|
|
37
|
+
(0, output_1.printSuccess)("Card " + (0, output_1.muted)((0, shared_1.maskCard)(card.last4)) + " is now frozen.");
|
|
38
|
+
console.log();
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
exports.cardUnfreezeCommand = new commander_1.Command("unfreeze")
|
|
42
|
+
.description("Unfreeze a virtual card")
|
|
43
|
+
.argument("<cardId>", "Card ID to unfreeze")
|
|
44
|
+
.option("--json", "Output as JSON")
|
|
45
|
+
.action(async (cardId, opts) => {
|
|
46
|
+
if (!(0, config_1.isAuthenticated)()) {
|
|
47
|
+
(0, output_1.printError)("Not authenticated. Run " + (0, output_1.accent)("code auth login") + " first.");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const spinner = (0, ora_1.default)({ text: "Unfreezing card...", color: "green" }).start();
|
|
51
|
+
const card = await (0, api_client_1.unfreezeCard)(cardId);
|
|
52
|
+
spinner.stop();
|
|
53
|
+
if (!card) {
|
|
54
|
+
if (opts.json)
|
|
55
|
+
(0, output_1.printJsonError)("Card not found");
|
|
56
|
+
else
|
|
57
|
+
(0, output_1.printError)("Card " + cardId + " not found.");
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (opts.json) {
|
|
61
|
+
(0, output_1.printJson)({ success: true, card });
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
(0, output_1.printHeader)("Card Unfrozen");
|
|
65
|
+
(0, output_1.printSuccess)("Card " + (0, output_1.muted)((0, shared_1.maskCard)(card.last4)) + " is now active.");
|
|
66
|
+
console.log();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.cardListCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const config_1 = require("../../lib/config");
|
|
10
|
+
const api_client_1 = require("../../lib/api-client");
|
|
11
|
+
const output_1 = require("../../lib/output");
|
|
12
|
+
const shared_1 = require("../../shared");
|
|
13
|
+
exports.cardListCommand = new commander_1.Command("list")
|
|
14
|
+
.description("List all virtual cards")
|
|
15
|
+
.option("--json", "Output as JSON")
|
|
16
|
+
.action(async (opts) => {
|
|
17
|
+
if (!(0, config_1.isAuthenticated)()) {
|
|
18
|
+
(0, output_1.printError)("Not authenticated. Run " + (0, output_1.accent)("code auth login") + " first.");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const spinner = (0, ora_1.default)({ text: "Fetching cards...", color: "green" }).start();
|
|
22
|
+
const [cards, projects] = await Promise.all([(0, api_client_1.getCards)(), (0, api_client_1.getProjects)()]);
|
|
23
|
+
spinner.stop();
|
|
24
|
+
if (opts.json) {
|
|
25
|
+
(0, output_1.printJson)(cards);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const active = cards.filter((c) => c.status === "active").length;
|
|
29
|
+
const frozen = cards.filter((c) => c.status === "frozen").length;
|
|
30
|
+
(0, output_1.printHeader)(`Cards (${active} active, ${frozen} frozen)`);
|
|
31
|
+
const table = (0, output_1.createTable)(["Card", "Project", "Status", "Spend / Limit"]);
|
|
32
|
+
for (const c of cards) {
|
|
33
|
+
const project = projects.find((p) => p.id === c.projectId);
|
|
34
|
+
const statusColor = c.status === "active" ? output_1.accent : c.status === "frozen" ? output_1.pink : output_1.dim;
|
|
35
|
+
table.push([
|
|
36
|
+
(0, output_1.muted)((0, shared_1.maskCard)(c.last4)),
|
|
37
|
+
project ? (0, output_1.accent)(project.name) : (0, output_1.dim)("personal"),
|
|
38
|
+
statusColor(c.status),
|
|
39
|
+
(0, output_1.muted)((0, shared_1.currency)(c.currentMonthSpend) + " / " + (0, shared_1.currency)(c.monthlyLimit)),
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
42
|
+
console.log(table.toString());
|
|
43
|
+
console.log();
|
|
44
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.pnlCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const config_1 = require("../lib/config");
|
|
10
|
+
const api_client_1 = require("../lib/api-client");
|
|
11
|
+
const output_1 = require("../lib/output");
|
|
12
|
+
const shared_1 = require("../shared");
|
|
13
|
+
exports.pnlCommand = new commander_1.Command("pnl")
|
|
14
|
+
.description("View project P&L")
|
|
15
|
+
.argument("<project>", "Project name")
|
|
16
|
+
.option("--json", "Output as JSON")
|
|
17
|
+
.action(async (projectName, opts) => {
|
|
18
|
+
if (!(0, config_1.isAuthenticated)()) {
|
|
19
|
+
(0, output_1.printError)("Not authenticated. Run " + (0, output_1.accent)("code auth login") + " first.");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const spinner = (0, ora_1.default)({ text: "Fetching P&L...", color: "green" }).start();
|
|
23
|
+
const projects = await (0, api_client_1.getProjects)();
|
|
24
|
+
const project = projects.find((p) => p.name === projectName);
|
|
25
|
+
if (!project) {
|
|
26
|
+
spinner.stop();
|
|
27
|
+
(0, output_1.printError)("Project " + (0, output_1.accent)('"' + projectName + '"') + " not found.");
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const pnl = await (0, api_client_1.getProjectPnl)(project.id);
|
|
31
|
+
spinner.stop();
|
|
32
|
+
if (!pnl) {
|
|
33
|
+
(0, output_1.printError)("No P&L data for " + (0, output_1.accent)(projectName));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (opts.json) {
|
|
37
|
+
(0, output_1.printJson)(pnl);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
(0, output_1.printHeader)(pnl.projectName + " │ " + pnl.period);
|
|
41
|
+
console.log();
|
|
42
|
+
(0, output_1.printRow)("Spend", (0, output_1.pink)((0, shared_1.currency)(pnl.spend)));
|
|
43
|
+
(0, output_1.printRow)("Revenue", (0, output_1.cyan)((0, shared_1.currency)(pnl.revenue)));
|
|
44
|
+
const netColor = pnl.net >= 0 ? output_1.accent : output_1.orange;
|
|
45
|
+
(0, output_1.printRow)("Net", netColor((pnl.net >= 0 ? "+" : "") + (0, shared_1.currency)(pnl.net)));
|
|
46
|
+
(0, output_1.printRow)("Margin", netColor((0, shared_1.percentage)(pnl.margin)));
|
|
47
|
+
console.log();
|
|
48
|
+
if (pnl.topProviders.length > 0) {
|
|
49
|
+
console.log((0, output_1.dim)(" Top Providers"));
|
|
50
|
+
const table = (0, output_1.createTable)(["Provider", "Amount"]);
|
|
51
|
+
for (const p of pnl.topProviders) {
|
|
52
|
+
table.push([(0, output_1.muted)(p.name), (0, shared_1.currency)(p.amount)]);
|
|
53
|
+
}
|
|
54
|
+
console.log(table.toString());
|
|
55
|
+
}
|
|
56
|
+
console.log();
|
|
57
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.projectCreateCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const config_1 = require("../../lib/config");
|
|
10
|
+
const api_client_1 = require("../../lib/api-client");
|
|
11
|
+
const output_1 = require("../../lib/output");
|
|
12
|
+
const shared_1 = require("../../shared");
|
|
13
|
+
exports.projectCreateCommand = new commander_1.Command("create")
|
|
14
|
+
.description("Create a new project with a virtual card")
|
|
15
|
+
.argument("<name>", "Project name")
|
|
16
|
+
.option("-d, --description <desc>", "Project description", "")
|
|
17
|
+
.option("-b, --budget <amount>", "Monthly budget in dollars", "2000")
|
|
18
|
+
.option("--json", "Output as JSON")
|
|
19
|
+
.action(async (name, opts) => {
|
|
20
|
+
if (!(0, config_1.isAuthenticated)()) {
|
|
21
|
+
(0, output_1.printError)("Not authenticated. Run " + (0, output_1.accent)("code auth login") + " first.");
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const spinner = (0, ora_1.default)({ text: "Creating project...", color: "green" }).start();
|
|
25
|
+
const project = await (0, api_client_1.createProject)(name, opts.description, parseInt(opts.budget, 10));
|
|
26
|
+
spinner.succeed("Project created");
|
|
27
|
+
if (opts.json) {
|
|
28
|
+
(0, output_1.printJson)(project);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
(0, output_1.printHeader)("Project Created");
|
|
32
|
+
(0, output_1.printSuccess)("Project " + (0, output_1.accent)('"' + project.name + '"') + " created");
|
|
33
|
+
(0, output_1.printSuccess)("Card " + (0, output_1.muted)((0, shared_1.maskCard)(project.cardId.slice(-4))) + " assigned");
|
|
34
|
+
(0, output_1.printSuccess)("Budget limit: " + (0, output_1.accent)("$" + project.monthlyBudget.toLocaleString() + "/mo"));
|
|
35
|
+
console.log();
|
|
36
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.projectListCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const config_1 = require("../../lib/config");
|
|
10
|
+
const api_client_1 = require("../../lib/api-client");
|
|
11
|
+
const output_1 = require("../../lib/output");
|
|
12
|
+
const shared_1 = require("../../shared");
|
|
13
|
+
exports.projectListCommand = new commander_1.Command("list")
|
|
14
|
+
.description("List all projects")
|
|
15
|
+
.option("--json", "Output as JSON")
|
|
16
|
+
.action(async (opts) => {
|
|
17
|
+
if (!(0, config_1.isAuthenticated)()) {
|
|
18
|
+
(0, output_1.printError)("Not authenticated. Run " + (0, output_1.accent)("code auth login") + " first.");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const spinner = (0, ora_1.default)({ text: "Fetching projects...", color: "green" }).start();
|
|
22
|
+
const projects = await (0, api_client_1.getProjects)();
|
|
23
|
+
spinner.stop();
|
|
24
|
+
if (opts.json) {
|
|
25
|
+
(0, output_1.printJson)(projects);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
(0, output_1.printHeader)(`Projects (${projects.length})`);
|
|
29
|
+
const table = (0, output_1.createTable)(["", "Name", "Status", "Budget", "Card"]);
|
|
30
|
+
for (const p of projects) {
|
|
31
|
+
const statusColor = p.status === "active" ? output_1.accent : p.status === "paused" ? output_1.muted : output_1.dim;
|
|
32
|
+
table.push([
|
|
33
|
+
"●",
|
|
34
|
+
(0, output_1.accent)(p.name),
|
|
35
|
+
statusColor(p.status),
|
|
36
|
+
(0, output_1.muted)((0, shared_1.currency)(p.monthlyBudget) + "/mo"),
|
|
37
|
+
(0, output_1.dim)("•••• " + p.cardId.slice(-3)),
|
|
38
|
+
]);
|
|
39
|
+
}
|
|
40
|
+
console.log(table.toString());
|
|
41
|
+
console.log();
|
|
42
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.rewardsCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const config_1 = require("../lib/config");
|
|
10
|
+
const api_client_1 = require("../lib/api-client");
|
|
11
|
+
const output_1 = require("../lib/output");
|
|
12
|
+
const shared_1 = require("../shared");
|
|
13
|
+
const tierColors = [output_1.accent, output_1.blue, output_1.purple, output_1.orange];
|
|
14
|
+
exports.rewardsCommand = new commander_1.Command("rewards")
|
|
15
|
+
.description("View rewards and Code Credits")
|
|
16
|
+
.option("--json", "Output as JSON")
|
|
17
|
+
.action(async (opts) => {
|
|
18
|
+
if (!(0, config_1.isAuthenticated)()) {
|
|
19
|
+
(0, output_1.printError)("Not authenticated. Run " + (0, output_1.accent)("code auth login") + " first.");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const spinner = (0, ora_1.default)({ text: "Fetching rewards...", color: "green" }).start();
|
|
23
|
+
const { balance, tiers, history } = await (0, api_client_1.getRewards)();
|
|
24
|
+
spinner.stop();
|
|
25
|
+
if (opts.json) {
|
|
26
|
+
(0, output_1.printJson)({ balance, tiers, history });
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
(0, output_1.printHeader)("Code Credits");
|
|
30
|
+
(0, output_1.printRow)("Available", (0, output_1.accent)((0, shared_1.currency)(balance.totalCredits)));
|
|
31
|
+
(0, output_1.printRow)("Pending", (0, output_1.muted)((0, shared_1.currency)(balance.pendingCredits)));
|
|
32
|
+
(0, output_1.printRow)("Lifetime earned", (0, shared_1.currency)(balance.lifetimeEarned));
|
|
33
|
+
(0, output_1.printRow)("Lifetime redeemed", (0, shared_1.currency)(balance.lifetimeRedeemed));
|
|
34
|
+
console.log();
|
|
35
|
+
// Tiers
|
|
36
|
+
console.log((0, output_1.dim)(" Reward Tiers"));
|
|
37
|
+
const table = (0, output_1.createTable)(["Category", "Rate", "Earned", "On Spend"]);
|
|
38
|
+
tiers.forEach((t, i) => {
|
|
39
|
+
const colorFn = tierColors[i] || output_1.muted;
|
|
40
|
+
table.push([
|
|
41
|
+
colorFn(t.category),
|
|
42
|
+
colorFn(t.rate + "%"),
|
|
43
|
+
(0, shared_1.currency)(t.earned),
|
|
44
|
+
(0, output_1.dim)((0, shared_1.currency)(t.spend)),
|
|
45
|
+
]);
|
|
46
|
+
});
|
|
47
|
+
console.log(table.toString());
|
|
48
|
+
// Recent history
|
|
49
|
+
console.log((0, output_1.dim)(" Recent Activity"));
|
|
50
|
+
const histTable = (0, output_1.createTable)(["Type", "Amount", "Description"]);
|
|
51
|
+
for (const h of history.slice(0, 5)) {
|
|
52
|
+
const colorFn = h.type === "earned" ? output_1.accent : output_1.muted;
|
|
53
|
+
histTable.push([
|
|
54
|
+
colorFn(h.type),
|
|
55
|
+
colorFn(h.amount > 0 ? "+" + (0, shared_1.currency)(h.amount) : (0, shared_1.currency)(h.amount)),
|
|
56
|
+
(0, output_1.dim)(h.description),
|
|
57
|
+
]);
|
|
58
|
+
}
|
|
59
|
+
console.log(histTable.toString());
|
|
60
|
+
console.log();
|
|
61
|
+
});
|