repofence 0.1.5 → 0.1.7

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/README.md CHANGED
@@ -126,6 +126,33 @@ After running `init`, open any project in Cursor and type `/repofence.help` in t
126
126
  | `--dry-run` | Show what would be done without making changes |
127
127
  | `--verbose` | Enable verbose logging |
128
128
 
129
+ ## HTTP API (backend in this repo)
130
+
131
+ The same repository includes the **Repofence API** under `backend/`. Canonical entry: **`backend/server.ts`**.
132
+
133
+ | Script | Purpose |
134
+ |--------|---------|
135
+ | `npm run backend` | Run API locally with `ts-node` (port `3002` or `PORT`) |
136
+ | `npm run build:backend` | Compile API to `backend-dist/` |
137
+ | `npm run backend:start` | Run compiled API: `node backend-dist/server.js` |
138
+ | `npm start` | Same as API server (`backend-dist/server.js`) — matches **Railway** default |
139
+ | `npm run start:cli` | Run compiled CLI entry (`dist/cli.js`) locally |
140
+
141
+ Deploy (e.g. **Railway**): see [`backend/README.md`](backend/README.md) and root **`railway.json`**.
142
+
143
+ ## Publishing the CLI (npm)
144
+
145
+ Step-by-step: **[docs/RELEASE.md](docs/RELEASE.md)** (`npm version`, `npm publish`). The published package only includes **`dist/`**; the HTTP API in `backend/` is deployed separately.
146
+
147
+ ## Environment variables
148
+
149
+ | Variable | Description |
150
+ |----------|-------------|
151
+ | `REPOFENCE_API_BASE_URL` | API host for the CLI (`auth`, `init`). Default normalizes to `…/api`. |
152
+ | `REPOFENCE_MOCK` | Set to `1` for mock API responses (no network). |
153
+ | `REPOFENCE_PACK_ID` | Pack id for `repofence init` (default: `core`). |
154
+ | `REPOFENCE_PUBLIC_KEY` | Optional. PEM or base64 public key to verify signed packs. If unset, the CLI uses its built-in public key. |
155
+
129
156
  ## Requirements
130
157
 
131
158
  - Node.js 18 or higher
@@ -144,8 +144,10 @@ async function initCommand(cwd, options) {
144
144
  process.exit(1);
145
145
  }
146
146
  const client = new api_client_1.ApiClient();
147
+ const resolvedBase = (0, api_client_1.getResolvedApiBaseUrl)();
147
148
  if (verbose) {
148
- console.log(chalk_1.default.cyan(`[debug] REPOFENCE_API_BASE_URL=${process.env.REPOFENCE_API_BASE_URL || '(default)'}`));
149
+ console.log(chalk_1.default.cyan(`[debug] REPOFENCE_API_BASE_URL(raw)=${process.env.REPOFENCE_API_BASE_URL || '(unset)'}`));
150
+ console.log(chalk_1.default.cyan(`[debug] resolved API base=${resolvedBase}`));
149
151
  console.log(chalk_1.default.cyan(`[debug] REPOFENCE_PACK_ID=${packId}`));
150
152
  }
151
153
  let pack = null;
@@ -154,8 +156,7 @@ async function initCommand(cwd, options) {
154
156
  }
155
157
  catch (error) {
156
158
  const message = error instanceof Error ? error.message : String(error);
157
- const baseUrl = process.env.REPOFENCE_API_BASE_URL || '(default: https://api.repofence.com)';
158
- console.error(chalk_1.default.red(`❌ Error al descargar pack "${packId}" (${baseUrl}): ${message}`));
159
+ console.error(chalk_1.default.red(`❌ Error al descargar pack "${packId}" (${resolvedBase}): ${message}`));
159
160
  throw error;
160
161
  }
161
162
  const isValid = await (0, pack_manager_1.validateSignature)(pack);
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ApiClient = exports.ApiClientError = void 0;
4
+ exports.normalizeApiBaseUrl = normalizeApiBaseUrl;
5
+ exports.getResolvedApiBaseUrl = getResolvedApiBaseUrl;
4
6
  class ApiClientError extends Error {
5
7
  constructor(message, status, code, details) {
6
8
  super(message);
@@ -30,9 +32,28 @@ const DEMO_PACK = {
30
32
  const notImplemented = () => {
31
33
  throw new Error('API client no implementado. Usa REPOFENCE_MOCK=1 para datos dummy.');
32
34
  };
35
+ /**
36
+ * Production hosts expose routes under `/api/v1/...`.
37
+ * Accept either `https://host` or `https://host/api` — paths in this client stay `/v1/...`.
38
+ */
39
+ function normalizeApiBaseUrl(raw) {
40
+ const trimmed = raw.replace(/\/+$/, '');
41
+ if (!trimmed) {
42
+ return 'https://api.repofence.com/api';
43
+ }
44
+ if (trimmed.endsWith('/api')) {
45
+ return trimmed;
46
+ }
47
+ return `${trimmed}/api`;
48
+ }
49
+ /** Base URL used for all HTTP calls (env + default + `/api` segment). */
50
+ function getResolvedApiBaseUrl(override) {
51
+ const raw = override ?? process.env.REPOFENCE_API_BASE_URL ?? 'https://api.repofence.com';
52
+ return normalizeApiBaseUrl(raw);
53
+ }
33
54
  class ApiClient {
34
55
  constructor(baseUrl) {
35
- this.baseUrl = baseUrl || process.env.REPOFENCE_API_BASE_URL || 'https://api.repofence.com';
56
+ this.baseUrl = getResolvedApiBaseUrl(baseUrl);
36
57
  }
37
58
  async request(path, init) {
38
59
  // Ensure we don't drop the /api segment if path starts with "/"
@@ -9,6 +9,7 @@ const os_1 = __importDefault(require("os"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const crypto_1 = __importDefault(require("crypto"));
11
11
  const tar_1 = __importDefault(require("tar"));
12
+ const pack_public_key_1 = require("./pack-public-key");
12
13
  const defaultCommandsDir = () => process.env.REPOFENCE_COMMANDS_DIR || path_1.default.join(os_1.default.homedir(), '.cursor', 'commands');
13
14
  const commandsDir = (baseDir) => baseDir || defaultCommandsDir();
14
15
  const manifestPath = (baseDir) => path_1.default.join(commandsDir(baseDir), '.repofence-manifest.json');
@@ -151,13 +152,10 @@ const validateSignature = async (_pack) => {
151
152
  const payloadToVerify = pack.archiveHash
152
153
  ? `${pack.manifestHash}:${pack.archiveHash}`
153
154
  : pack.manifestHash;
154
- const publicKeyEnv = process.env.REPOFENCE_PUBLIC_KEY;
155
- if (!publicKeyEnv) {
156
- throw new Error('Falta REPOFENCE_PUBLIC_KEY para validar la firma del pack.');
157
- }
158
- const publicKeyPem = publicKeyEnv.includes('BEGIN')
159
- ? publicKeyEnv
160
- : Buffer.from(publicKeyEnv, 'base64').toString('utf8');
155
+ const rawKey = process.env.REPOFENCE_PUBLIC_KEY?.trim() || pack_public_key_1.EMBEDDED_PACK_PUBLIC_KEY_PEM;
156
+ const publicKeyPem = rawKey.includes('BEGIN')
157
+ ? rawKey
158
+ : Buffer.from(rawKey, 'base64').toString('utf8');
161
159
  try {
162
160
  const keyObject = crypto_1.default.createPublicKey(publicKeyPem);
163
161
  const isValid = crypto_1.default.verify(null, Buffer.from(payloadToVerify), keyObject, Buffer.from(pack.signature, 'base64'));
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EMBEDDED_PACK_PUBLIC_KEY_PEM = void 0;
4
+ /**
5
+ * Default Ed25519 public key for verifying signed packs from the Repofence API.
6
+ * Keep in sync with `public_key.pem` at the repo root (pair to backend REPOFENCE_SIGNING_KEY).
7
+ * Override with env REPOFENCE_PUBLIC_KEY for testing or key rotation.
8
+ */
9
+ exports.EMBEDDED_PACK_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
10
+ LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUNvd0JRWURLMlZ3QXlFQUpUZnhjN2JhVzg1dzdyM3V4YllOdWFaUk1vZTFlMmxjdmEybDdNTzBpYWs9Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=
11
+ -----END PUBLIC KEY-----
12
+ `;
13
+ //# sourceMappingURL=pack-public-key.js.map
package/package.json CHANGED
@@ -1,17 +1,26 @@
1
1
  {
2
2
  "name": "repofence",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Repofence CLI (packs + backend auth)",
5
5
  "main": "dist/cli.js",
6
6
  "bin": {
7
7
  "repofence": "./dist/cli.js"
8
8
  },
9
+ "files": [
10
+ "dist/**/*.js",
11
+ "dist/templates/**/*.md"
12
+ ],
9
13
  "scripts": {
10
14
  "build": "tsc && npm run copy-templates && npm run add-shebang",
15
+ "build:backend": "tsc -p backend/tsconfig.json",
16
+ "build:all": "npm run build && npm run build:backend",
11
17
  "copy-templates": "node scripts/copy-templates.js",
12
18
  "add-shebang": "node scripts/add-shebang.js",
13
- "start": "node dist/cli.js",
14
- "dev": "ts-node src/cli.ts"
19
+ "start": "node backend-dist/server.js",
20
+ "start:cli": "node dist/cli.js",
21
+ "dev": "ts-node src/cli.ts",
22
+ "backend": "ts-node backend/server.ts",
23
+ "backend:start": "node backend-dist/server.js"
15
24
  },
16
25
  "keywords": [
17
26
  "sdd",
@@ -24,7 +33,7 @@
24
33
  "dependencies": {
25
34
  "@aws-sdk/client-s3": "^3.705.0",
26
35
  "@aws-sdk/s3-request-presigner": "^3.705.0",
27
- "chalk": "^5.6.2",
36
+ "chalk": "^4.1.2",
28
37
  "commander": "^11.1.0",
29
38
  "dotenv": "^16.4.5",
30
39
  "open": "^11.0.0",