@stainlu/faam-cli 0.2.1 → 0.2.4

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 ADDED
@@ -0,0 +1,31 @@
1
+ # Changelog
2
+
3
+ ## 0.2.4 (2026-02-10)
4
+
5
+ - Fix CI workflow (pin pnpm version)
6
+
7
+ ## 0.2.3 (2026-02-10)
8
+
9
+ - Add npm badges, Security & Safety section, and install-skills docs to README
10
+ - Add SECURITY.md and CHANGELOG.md
11
+ - Add package metadata (homepage, author, bugs, funding, expanded keywords)
12
+ - Set up GitHub Actions for npm provenance attestation
13
+ - Fix license text in README (was incorrectly listed as MIT)
14
+
15
+ ## 0.2.2 (2026-02-09)
16
+
17
+ - Dynamic version display (reads from package.json)
18
+ - Fix `install-skills` authentication (use Bearer token)
19
+ - Rebrand rlp → faam across all CLI output
20
+
21
+ ## 0.2.1 (2026-02-09)
22
+
23
+ - Use Authorization header instead of query params for API requests
24
+
25
+ ## 0.2.0 (2026-02-08)
26
+
27
+ - Add `install-skills` command — download personalized skills from FAAM
28
+ - Add `config` command — manage agent card configuration
29
+ - All-in-one `init` command with auto-discovery and auto-sync
30
+ - Support for multiple agents: Claude Code, Codex, Cursor, OpenCode, Windsurf
31
+ - Auto-migration from `~/.rlp/` to `~/.faam/`
package/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # FAAM CLI
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/@stainlu/faam-cli)](https://www.npmjs.com/package/@stainlu/faam-cli)
4
+ [![license](https://img.shields.io/npm/l/@stainlu/faam-cli)](https://github.com/stainlu/faam/blob/main/apps/cli/LICENSE)
5
+ [![downloads](https://img.shields.io/npm/dm/@stainlu/faam-cli)](https://www.npmjs.com/package/@stainlu/faam-cli)
6
+ [![node](https://img.shields.io/node/v/@stainlu/faam-cli)](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.
@@ -116,6 +121,31 @@ Options:
116
121
  - `-p, --path <directory>` - Custom skills directory path
117
122
  - `--no-delete` - Don't delete remote skills that are not in local
118
123
 
124
+ ### `faam install-skills`
125
+
126
+ 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.
127
+
128
+ ```bash
129
+ # Install to default agents (Claude Code + Codex)
130
+ faam install-skills
131
+
132
+ # Install to a specific agent
133
+ faam install-skills --agent claude-code
134
+
135
+ # Install to project directory instead of global
136
+ faam install-skills --no-global
137
+
138
+ # Overwrite existing skills
139
+ faam install-skills --force
140
+ ```
141
+
142
+ Options:
143
+ - `--agent <name>` - Target agent (claude-code, codex, cursor, opencode, windsurf)
144
+ - `--no-global` - Install to project directory instead of `~/`
145
+ - `-f, --force` - Overwrite existing skill files
146
+
147
+ Supported agents: `claude-code`, `codex`, `cursor`, `opencode`, `windsurf`
148
+
119
149
  ### `faam status`
120
150
 
121
151
  Show current account and skills sync status.
@@ -206,10 +236,33 @@ Defines your agent card metadata. Create with `faam init` or edit directly:
206
236
 
207
237
  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
238
 
239
+ ## Security & Safety
240
+
241
+ This CLI is fully open source ([Apache-2.0](./LICENSE)). Here's exactly what it does and doesn't do:
242
+
243
+ **Data stored locally** (`~/.faam/`):
244
+ - `config.json` — your account key and API URL
245
+ - `agent-card.json` — your agent card metadata
246
+
247
+ **What each command does**:
248
+ - `sync-skills` — reads SKILL.md files from your local skills directories and uploads their metadata (name, description, tags) to the FAAM API
249
+ - `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.
250
+ - `init` / `config` — manage local JSON configuration and sync to the API
251
+ - `login` / `logout` — store or remove your account key locally
252
+
253
+ **What this CLI does NOT do**:
254
+ - Run any downloaded code or scripts
255
+ - Install system packages or dependencies
256
+ - Access files outside of `~/.faam/` and your agent's skills directories
257
+ - Send telemetry or analytics
258
+ - Run background processes or auto-update
259
+
260
+ See [SECURITY.md](./SECURITY.md) for our security policy.
261
+
209
262
  ## Migration from rlp-cli
210
263
 
211
264
  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
265
 
213
266
  ## License
214
267
 
215
- MIT
268
+ 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
@@ -14743,6 +14743,23 @@ var RlpApiClient = class {
14743
14743
  throw new Error(error.error || `API error: ${response.status}`);
14744
14744
  }
14745
14745
  }
14746
+ /**
14747
+ * Get personalized skills for the account
14748
+ */
14749
+ async getPersonalizedSkills() {
14750
+ const url = `${this.apiUrl}/api/skills/me`;
14751
+ const response = await fetch(url, {
14752
+ headers: this.authHeaders
14753
+ });
14754
+ if (!response.ok) {
14755
+ if (response.status === 404) {
14756
+ return { skills: [] };
14757
+ }
14758
+ const error = await response.json().catch(() => ({ error: "Unknown error" }));
14759
+ throw new Error(error.error || `API error: ${response.status}`);
14760
+ }
14761
+ return response.json();
14762
+ }
14746
14763
  /**
14747
14764
  * Validate account key by fetching profile
14748
14765
  * Returns account_id if valid
@@ -22039,15 +22056,8 @@ async function installSkillsCommand(options2) {
22039
22056
  }
22040
22057
  const fetchSpinner = ora("Fetching personalized skills...").start();
22041
22058
  try {
22042
- const url = `${config.api_url}/api/skills/me?account_key=${encodeURIComponent(config.account_key)}`;
22043
- const response = await fetch(url);
22044
- if (!response.ok) {
22045
- const error = await response.json().catch(() => ({ error: "Unknown error" }));
22046
- fetchSpinner.fail("Failed to fetch skills");
22047
- console.error(source_default.red(error.error || `API error: ${response.status}`));
22048
- process.exit(1);
22049
- }
22050
- const data = await response.json();
22059
+ const client = new RlpApiClient(config);
22060
+ const data = await client.getPersonalizedSkills();
22051
22061
  if (data.error) {
22052
22062
  fetchSpinner.fail("Failed to fetch skills");
22053
22063
  console.error(source_default.red(data.error));
@@ -22374,7 +22384,7 @@ function configShowCommand() {
22374
22384
  if (!agentCardConfigExists()) {
22375
22385
  console.log(source_default.yellow("No agent-card.json found."));
22376
22386
  console.log();
22377
- console.log("Run", source_default.cyan("rlp init"), "to create one, or use", source_default.cyan("rlp config set <key> <value>"));
22387
+ console.log("Run", source_default.cyan("faam init"), "to create one, or use", source_default.cyan("faam config set <key> <value>"));
22378
22388
  console.log();
22379
22389
  console.log("Config path:", source_default.gray(configPath));
22380
22390
  return;
@@ -22388,7 +22398,7 @@ function configShowCommand() {
22388
22398
  function configGetCommand(key) {
22389
22399
  if (!agentCardConfigExists()) {
22390
22400
  console.log(source_default.yellow("No agent-card.json found."));
22391
- console.log("Run", source_default.cyan("rlp init"), "to create one.");
22401
+ console.log("Run", source_default.cyan("faam init"), "to create one.");
22392
22402
  return;
22393
22403
  }
22394
22404
  const config = readAgentCardConfig();
@@ -22430,7 +22440,7 @@ async function autoSync(config) {
22430
22440
  if (!isLoggedIn()) {
22431
22441
  console.log();
22432
22442
  console.log(source_default.gray("Not logged in - changes saved locally only."));
22433
- console.log("Run", source_default.cyan("rlp login --key <key>"), "then", source_default.cyan("rlp sync-skills"), "to sync.");
22443
+ console.log("Run", source_default.cyan("faam login --key <key>"), "then", source_default.cyan("faam sync-skills"), "to sync.");
22434
22444
  return;
22435
22445
  }
22436
22446
  console.log();
@@ -22444,7 +22454,7 @@ async function autoSync(config) {
22444
22454
  } catch (err) {
22445
22455
  spinner.fail("Sync failed");
22446
22456
  console.error(source_default.red(err instanceof Error ? err.message : "Unknown error"));
22447
- console.log("You can retry with:", source_default.cyan("rlp sync-skills"));
22457
+ console.log("You can retry with:", source_default.cyan("faam sync-skills"));
22448
22458
  }
22449
22459
  }
22450
22460
  function configListKeysCommand() {
@@ -22470,14 +22480,14 @@ function configListKeysCommand() {
22470
22480
  }
22471
22481
  console.log();
22472
22482
  console.log("Example usage:");
22473
- console.log(` ${source_default.gray('rlp config set name "My AI Agent"')}`);
22474
- console.log(` ${source_default.gray('rlp config set provider.organization "My Company"')}`);
22475
- console.log(` ${source_default.gray("rlp config set capabilities.streaming true")}`);
22483
+ console.log(` ${source_default.gray('faam config set name "My AI Agent"')}`);
22484
+ console.log(` ${source_default.gray('faam config set provider.organization "My Company"')}`);
22485
+ console.log(` ${source_default.gray("faam config set capabilities.streaming true")}`);
22476
22486
  }
22477
22487
 
22478
22488
  // src/index.ts
22479
22489
  var program2 = new Command();
22480
- program2.name("faam").description("CLI tool to sync local skills to your FAAM Agent Card").version("0.2.0");
22490
+ program2.name("faam").description("CLI tool to sync local skills to your FAAM Agent Card").version("0.2.4");
22481
22491
  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) => {
22482
22492
  await loginCommand({
22483
22493
  key: options2.key,
package/package.json CHANGED
@@ -1,17 +1,12 @@
1
1
  {
2
2
  "name": "@stainlu/faam-cli",
3
- "version": "0.2.1",
3
+ "version": "0.2.4",
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
+ }