@stainlu/faam-cli 0.2.2 → 0.2.5
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/CHANGELOG.md +36 -0
- package/README.md +63 -7
- package/SECURITY.md +53 -0
- package/dist/index.cjs +16 -26
- package/package.json +20 -9
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.5 (2026-02-10)
|
|
4
|
+
|
|
5
|
+
- `faam init` now works with zero arguments — name auto-generates, description optional
|
|
6
|
+
- API no longer requires description for agent profile
|
|
7
|
+
|
|
8
|
+
## 0.2.4 (2026-02-10)
|
|
9
|
+
|
|
10
|
+
- Fix CI workflow (pin pnpm version)
|
|
11
|
+
|
|
12
|
+
## 0.2.3 (2026-02-10)
|
|
13
|
+
|
|
14
|
+
- Add npm badges, Security & Safety section, and install-skills docs to README
|
|
15
|
+
- Add SECURITY.md and CHANGELOG.md
|
|
16
|
+
- Add package metadata (homepage, author, bugs, funding, expanded keywords)
|
|
17
|
+
- Set up GitHub Actions for npm provenance attestation
|
|
18
|
+
- Fix license text in README (was incorrectly listed as MIT)
|
|
19
|
+
|
|
20
|
+
## 0.2.2 (2026-02-09)
|
|
21
|
+
|
|
22
|
+
- Dynamic version display (reads from package.json)
|
|
23
|
+
- Fix `install-skills` authentication (use Bearer token)
|
|
24
|
+
- Rebrand rlp → faam across all CLI output
|
|
25
|
+
|
|
26
|
+
## 0.2.1 (2026-02-09)
|
|
27
|
+
|
|
28
|
+
- Use Authorization header instead of query params for API requests
|
|
29
|
+
|
|
30
|
+
## 0.2.0 (2026-02-08)
|
|
31
|
+
|
|
32
|
+
- Add `install-skills` command — download personalized skills from FAAM
|
|
33
|
+
- Add `config` command — manage agent card configuration
|
|
34
|
+
- All-in-one `init` command with auto-discovery and auto-sync
|
|
35
|
+
- Support for multiple agents: Claude Code, Codex, Cursor, OpenCode, Windsurf
|
|
36
|
+
- Auto-migration from `~/.rlp/` to `~/.faam/`
|
package/README.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# FAAM CLI
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@stainlu/faam-cli)
|
|
4
|
+
[](https://github.com/stainlu/faam/blob/main/apps/cli/LICENSE)
|
|
5
|
+
[](https://www.npmjs.com/package/@stainlu/faam-cli)
|
|
6
|
+
[](https://nodejs.org)
|
|
7
|
+
|
|
3
8
|
**Make your local AI agent discoverable to the world.**
|
|
4
9
|
|
|
5
10
|
Local AI agents like Claude Code, Codex, and Clawdbot have powerful skills but are invisible to others. Google's A2A (Agent-to-Agent) protocol defines `/.well-known/agent-card.json` for agent discovery, but local agents can't host their own files.
|
|
@@ -59,24 +64,27 @@ faam logout
|
|
|
59
64
|
|
|
60
65
|
### `faam init`
|
|
61
66
|
|
|
62
|
-
Initialize your agent card
|
|
67
|
+
Initialize your agent card, auto-discover skills, and sync to API. Works with zero arguments — name auto-generates from your account ID and description is optional.
|
|
63
68
|
|
|
64
69
|
```bash
|
|
65
|
-
#
|
|
70
|
+
# Zero-config (auto-generates name, no description)
|
|
66
71
|
faam init
|
|
67
72
|
|
|
68
|
-
#
|
|
73
|
+
# With custom name
|
|
74
|
+
faam init --name "My AI Agent"
|
|
75
|
+
|
|
76
|
+
# With name and description
|
|
69
77
|
faam init --name "My AI Agent" --description "What my agent does"
|
|
70
78
|
```
|
|
71
79
|
|
|
72
80
|
Options:
|
|
73
|
-
- `-n, --name <name>` - Agent name
|
|
74
|
-
- `-d, --description <desc>` - Agent description
|
|
81
|
+
- `-n, --name <name>` - Agent name (default: `agent-<account_id>`)
|
|
82
|
+
- `-d, --description <desc>` - Agent description (optional)
|
|
75
83
|
- `-o, --organization <org>` - Provider organization (optional)
|
|
76
84
|
- `-f, --force` - Overwrite existing config file
|
|
77
85
|
|
|
78
86
|
**Features:**
|
|
79
|
-
- **
|
|
87
|
+
- **Zero-config**: Run `faam init` with no arguments — name auto-generates, description is optional
|
|
80
88
|
- **Auto-discovery**: Finds skills from `~/.claude/skills/`, `.claude/skills/`, etc.
|
|
81
89
|
- **Auto-sync**: Immediately syncs to API when logged in
|
|
82
90
|
|
|
@@ -116,6 +124,31 @@ Options:
|
|
|
116
124
|
- `-p, --path <directory>` - Custom skills directory path
|
|
117
125
|
- `--no-delete` - Don't delete remote skills that are not in local
|
|
118
126
|
|
|
127
|
+
### `faam install-skills`
|
|
128
|
+
|
|
129
|
+
Download your personalized skills from FAAM and save them locally. This is completely optional — it fetches SKILL.md files (plain markdown instructions) based on your profile and saves them to your agent's skills directory. No executable code is downloaded or run.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Install to default agents (Claude Code + Codex)
|
|
133
|
+
faam install-skills
|
|
134
|
+
|
|
135
|
+
# Install to a specific agent
|
|
136
|
+
faam install-skills --agent claude-code
|
|
137
|
+
|
|
138
|
+
# Install to project directory instead of global
|
|
139
|
+
faam install-skills --no-global
|
|
140
|
+
|
|
141
|
+
# Overwrite existing skills
|
|
142
|
+
faam install-skills --force
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Options:
|
|
146
|
+
- `--agent <name>` - Target agent (claude-code, codex, cursor, opencode, windsurf)
|
|
147
|
+
- `--no-global` - Install to project directory instead of `~/`
|
|
148
|
+
- `-f, --force` - Overwrite existing skill files
|
|
149
|
+
|
|
150
|
+
Supported agents: `claude-code`, `codex`, `cursor`, `opencode`, `windsurf`
|
|
151
|
+
|
|
119
152
|
### `faam status`
|
|
120
153
|
|
|
121
154
|
Show current account and skills sync status.
|
|
@@ -206,10 +239,33 @@ Defines your agent card metadata. Create with `faam init` or edit directly:
|
|
|
206
239
|
|
|
207
240
|
Skills can be defined in agent-card.json OR as SKILL.md files. If a skill ID exists in both, the SKILL.md file takes precedence.
|
|
208
241
|
|
|
242
|
+
## Security & Safety
|
|
243
|
+
|
|
244
|
+
This CLI is fully open source ([Apache-2.0](./LICENSE)). Here's exactly what it does and doesn't do:
|
|
245
|
+
|
|
246
|
+
**Data stored locally** (`~/.faam/`):
|
|
247
|
+
- `config.json` — your account key and API URL
|
|
248
|
+
- `agent-card.json` — your agent card metadata
|
|
249
|
+
|
|
250
|
+
**What each command does**:
|
|
251
|
+
- `sync-skills` — reads SKILL.md files from your local skills directories and uploads their metadata (name, description, tags) to the FAAM API
|
|
252
|
+
- `install-skills` — downloads SKILL.md files (plain markdown, not executable code) from the FAAM API and saves them to your agent's skills directory. This is the same format used by Claude Code, Codex, and other agents for skill discovery. Skill installation is a standard pattern across AI coding agents.
|
|
253
|
+
- `init` / `config` — manage local JSON configuration and sync to the API
|
|
254
|
+
- `login` / `logout` — store or remove your account key locally
|
|
255
|
+
|
|
256
|
+
**What this CLI does NOT do**:
|
|
257
|
+
- Run any downloaded code or scripts
|
|
258
|
+
- Install system packages or dependencies
|
|
259
|
+
- Access files outside of `~/.faam/` and your agent's skills directories
|
|
260
|
+
- Send telemetry or analytics
|
|
261
|
+
- Run background processes or auto-update
|
|
262
|
+
|
|
263
|
+
See [SECURITY.md](./SECURITY.md) for our security policy.
|
|
264
|
+
|
|
209
265
|
## Migration from rlp-cli
|
|
210
266
|
|
|
211
267
|
If you were using the previous `@stainlu/rlp-cli` package, the FAAM CLI will automatically migrate your config from `~/.rlp/` to `~/.faam/` on first run. No action required.
|
|
212
268
|
|
|
213
269
|
## License
|
|
214
270
|
|
|
215
|
-
|
|
271
|
+
Apache-2.0
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Reporting Vulnerabilities
|
|
4
|
+
|
|
5
|
+
If you discover a security vulnerability, please report it via:
|
|
6
|
+
|
|
7
|
+
- **Email**: stainlu@newtype-ai.org
|
|
8
|
+
- **GitHub Issues**: https://github.com/stainlu/faam/issues (for non-sensitive issues)
|
|
9
|
+
|
|
10
|
+
We will acknowledge reports within 48 hours and aim to release fixes promptly.
|
|
11
|
+
|
|
12
|
+
## Data Handling
|
|
13
|
+
|
|
14
|
+
### What is stored locally
|
|
15
|
+
|
|
16
|
+
All data is stored in `~/.faam/` as plain JSON:
|
|
17
|
+
|
|
18
|
+
- `config.json` — account key and API URL
|
|
19
|
+
- `agent-card.json` — agent card metadata (name, description, skills list)
|
|
20
|
+
|
|
21
|
+
### What is transmitted
|
|
22
|
+
|
|
23
|
+
- `sync-skills` sends skill metadata (name, description, tags) to `api.faam.io` over HTTPS
|
|
24
|
+
- `install-skills` downloads SKILL.md content (plain markdown) from `api.faam.io` over HTTPS
|
|
25
|
+
- All API requests use your account key for authentication via Bearer token
|
|
26
|
+
|
|
27
|
+
### What is NOT transmitted
|
|
28
|
+
|
|
29
|
+
- File contents outside of SKILL.md files
|
|
30
|
+
- System information, environment variables, or telemetry
|
|
31
|
+
- Any data without explicit user action (no background processes)
|
|
32
|
+
|
|
33
|
+
## File System Access
|
|
34
|
+
|
|
35
|
+
This CLI only accesses:
|
|
36
|
+
|
|
37
|
+
- `~/.faam/` — configuration storage (read/write)
|
|
38
|
+
- Agent skills directories — e.g. `~/.claude/skills/`, `~/.codex/skills/` (read for sync, write for install-skills)
|
|
39
|
+
|
|
40
|
+
No other directories are read from or written to.
|
|
41
|
+
|
|
42
|
+
## Dependencies
|
|
43
|
+
|
|
44
|
+
This package uses a minimal set of well-known dependencies:
|
|
45
|
+
|
|
46
|
+
- `commander` — CLI argument parsing
|
|
47
|
+
- `chalk` — terminal colors
|
|
48
|
+
- `ora` — terminal spinners
|
|
49
|
+
- `prompts` — interactive prompts
|
|
50
|
+
- `glob` — file pattern matching
|
|
51
|
+
- `gray-matter` — YAML frontmatter parsing
|
|
52
|
+
|
|
53
|
+
All dependencies are pinned and auditable.
|
package/dist/index.cjs
CHANGED
|
@@ -22215,7 +22215,7 @@ var import_prompts = __toESM(require_prompts3(), 1);
|
|
|
22215
22215
|
async function initCommand(options2) {
|
|
22216
22216
|
const configPath = getAgentCardConfigPath();
|
|
22217
22217
|
if (agentCardConfigExists() && !options2.force) {
|
|
22218
|
-
if (!process.stdin.isTTY || options2.name
|
|
22218
|
+
if (!process.stdin.isTTY || options2.name) {
|
|
22219
22219
|
console.log(source_default.yellow("agent-card.json already exists at:"));
|
|
22220
22220
|
console.log(source_default.gray(configPath));
|
|
22221
22221
|
console.log();
|
|
@@ -22233,23 +22233,23 @@ async function initCommand(options2) {
|
|
|
22233
22233
|
return;
|
|
22234
22234
|
}
|
|
22235
22235
|
}
|
|
22236
|
-
const
|
|
22236
|
+
const clientConfig = isLoggedIn() ? readConfig() : null;
|
|
22237
|
+
const defaultName = clientConfig?.account_id ? `agent-${clientConfig.account_id}` : "My AI Agent";
|
|
22238
|
+
const isInteractive2 = process.stdin.isTTY && !options2.name;
|
|
22237
22239
|
let config;
|
|
22238
22240
|
if (isInteractive2) {
|
|
22239
22241
|
const response = await (0, import_prompts.default)([
|
|
22240
22242
|
{
|
|
22241
22243
|
type: "text",
|
|
22242
22244
|
name: "name",
|
|
22243
|
-
message: "Agent name",
|
|
22244
|
-
initial: options2.name ||
|
|
22245
|
-
validate: (v) => v.length > 0 || "Name is required"
|
|
22245
|
+
message: "Agent name (press Enter for default)",
|
|
22246
|
+
initial: options2.name || defaultName
|
|
22246
22247
|
},
|
|
22247
22248
|
{
|
|
22248
22249
|
type: "text",
|
|
22249
22250
|
name: "description",
|
|
22250
|
-
message: "Description",
|
|
22251
|
-
initial: options2.description || ""
|
|
22252
|
-
validate: (v) => v.length > 0 || "Description is required"
|
|
22251
|
+
message: "Description (optional)",
|
|
22252
|
+
initial: options2.description || ""
|
|
22253
22253
|
},
|
|
22254
22254
|
{
|
|
22255
22255
|
type: "text",
|
|
@@ -22263,12 +22263,9 @@ async function initCommand(options2) {
|
|
|
22263
22263
|
process.exit(0);
|
|
22264
22264
|
}
|
|
22265
22265
|
});
|
|
22266
|
-
if (!response.name || !response.description) {
|
|
22267
|
-
return;
|
|
22268
|
-
}
|
|
22269
22266
|
config = {
|
|
22270
|
-
name: response.name,
|
|
22271
|
-
description: response.description,
|
|
22267
|
+
name: response.name || defaultName,
|
|
22268
|
+
description: response.description || "",
|
|
22272
22269
|
version: "1.0.0",
|
|
22273
22270
|
provider: {
|
|
22274
22271
|
organization: response.organization || "",
|
|
@@ -22285,16 +22282,9 @@ async function initCommand(options2) {
|
|
|
22285
22282
|
is_public: true
|
|
22286
22283
|
};
|
|
22287
22284
|
} else {
|
|
22288
|
-
if (!options2.name || !options2.description) {
|
|
22289
|
-
console.log(source_default.red("Error: --name and --description are required in non-interactive mode."));
|
|
22290
|
-
console.log();
|
|
22291
|
-
console.log("Usage:");
|
|
22292
|
-
console.log(source_default.cyan(' faam init --name "My Agent" --description "What my agent does"'));
|
|
22293
|
-
process.exit(1);
|
|
22294
|
-
}
|
|
22295
22285
|
config = {
|
|
22296
|
-
name: options2.name,
|
|
22297
|
-
description: options2.description,
|
|
22286
|
+
name: options2.name || defaultName,
|
|
22287
|
+
description: options2.description || "",
|
|
22298
22288
|
version: "1.0.0",
|
|
22299
22289
|
provider: {
|
|
22300
22290
|
organization: options2.organization || "",
|
|
@@ -22347,8 +22337,8 @@ async function initCommand(options2) {
|
|
|
22347
22337
|
console.log();
|
|
22348
22338
|
const syncSpinner = ora("Syncing to Faam...").start();
|
|
22349
22339
|
try {
|
|
22350
|
-
const
|
|
22351
|
-
const client = new RlpApiClient(
|
|
22340
|
+
const syncConfig = clientConfig || readConfig();
|
|
22341
|
+
const client = new RlpApiClient(syncConfig);
|
|
22352
22342
|
const result = await syncToApi(client, config, fileSkills);
|
|
22353
22343
|
syncSpinner.succeed("Synced successfully");
|
|
22354
22344
|
if (result.created.length > 0) {
|
|
@@ -22365,7 +22355,7 @@ async function initCommand(options2) {
|
|
|
22365
22355
|
}
|
|
22366
22356
|
console.log();
|
|
22367
22357
|
console.log("Your agent card is live at:");
|
|
22368
|
-
console.log(source_default.cyan(`https://agent-${
|
|
22358
|
+
console.log(source_default.cyan(`https://agent-${syncConfig.account_id}.faam.io/.well-known/agent-card.json`));
|
|
22369
22359
|
console.log();
|
|
22370
22360
|
console.log("Go back to the onboarding page and click", source_default.bold('"Verify Setup"'), "to continue.");
|
|
22371
22361
|
} catch (err) {
|
|
@@ -22487,7 +22477,7 @@ function configListKeysCommand() {
|
|
|
22487
22477
|
|
|
22488
22478
|
// src/index.ts
|
|
22489
22479
|
var program2 = new Command();
|
|
22490
|
-
program2.name("faam").description("CLI tool to sync local skills to your FAAM Agent Card").version("0.2.
|
|
22480
|
+
program2.name("faam").description("CLI tool to sync local skills to your FAAM Agent Card").version("0.2.5");
|
|
22491
22481
|
program2.command("login").description("Store your FAAM account key").requiredOption("-k, --key <account_key>", "Your FAAM account key").option("--api-url <url>", "API URL (default: https://api.faam.io)").action(async (options2) => {
|
|
22492
22482
|
await loginCommand({
|
|
22493
22483
|
key: options2.key,
|
package/package.json
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stainlu/faam-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "CLI tool to sync local skills to your FAAM Agent Card",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"faam": "./dist/index.cjs",
|
|
8
8
|
"faam-cli": "./dist/index.cjs"
|
|
9
9
|
},
|
|
10
|
-
"scripts": {
|
|
11
|
-
"dev": "tsx src/index.ts",
|
|
12
|
-
"build": "tsup",
|
|
13
|
-
"typecheck": "tsc --noEmit"
|
|
14
|
-
},
|
|
15
10
|
"dependencies": {
|
|
16
11
|
"chalk": "^5.3.0",
|
|
17
12
|
"commander": "^12.1.0",
|
|
@@ -30,19 +25,35 @@
|
|
|
30
25
|
"node": ">=18"
|
|
31
26
|
},
|
|
32
27
|
"files": [
|
|
33
|
-
"dist"
|
|
28
|
+
"dist",
|
|
29
|
+
"LICENSE",
|
|
30
|
+
"SECURITY.md",
|
|
31
|
+
"CHANGELOG.md"
|
|
34
32
|
],
|
|
35
33
|
"keywords": [
|
|
36
34
|
"faam",
|
|
37
35
|
"agent",
|
|
38
36
|
"skills",
|
|
39
37
|
"cli",
|
|
40
|
-
"a2a"
|
|
38
|
+
"a2a",
|
|
39
|
+
"a2a-protocol",
|
|
40
|
+
"agent-card",
|
|
41
|
+
"ai-agent",
|
|
42
|
+
"google-a2a"
|
|
41
43
|
],
|
|
44
|
+
"author": "stainlu <stainlu@newtype-ai.org>",
|
|
42
45
|
"license": "Apache-2.0",
|
|
46
|
+
"homepage": "https://faam.io",
|
|
47
|
+
"bugs": "https://github.com/stainlu/faam/issues",
|
|
48
|
+
"funding": "https://faam.io",
|
|
43
49
|
"repository": {
|
|
44
50
|
"type": "git",
|
|
45
51
|
"url": "https://github.com/stainlu/faam.git",
|
|
46
52
|
"directory": "apps/cli"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"dev": "tsx src/index.ts",
|
|
56
|
+
"build": "tsup",
|
|
57
|
+
"typecheck": "tsc --noEmit"
|
|
47
58
|
}
|
|
48
|
-
}
|
|
59
|
+
}
|