threadlines 0.1.4 → 0.1.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/README.md +59 -1
- package/dist/commands/check.js +16 -1
- package/dist/commands/init.js +9 -0
- package/dist/index.js +45 -0
- package/dist/utils/config.js +63 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -14,14 +14,72 @@ Or use with npx:
|
|
|
14
14
|
npx threadlines check
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
### 1. Initialize Your First Threadline
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx threadlines init
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This command:
|
|
26
|
+
- Creates a `/threadlines` directory in your project root
|
|
27
|
+
- Generates `threadlines/example.md` with a template threadline
|
|
28
|
+
- Provides instructions for setting up your API key
|
|
29
|
+
|
|
30
|
+
### 2. Configure API Key
|
|
31
|
+
|
|
32
|
+
Create a `.env.local` file in your project root:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
THREADLINE_API_KEY=your-api-key-here
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Important:** Make sure `.env.local` is in your `.gitignore` file!
|
|
39
|
+
|
|
40
|
+
For CI/CD environments, set `THREADLINE_API_KEY` as an environment variable in your platform settings.
|
|
41
|
+
|
|
42
|
+
### 3. Edit Your Threadline
|
|
43
|
+
|
|
44
|
+
Edit `threadlines/example.md` with your coding standards, then rename it to something descriptive (e.g., `error-handling.md`).
|
|
45
|
+
|
|
46
|
+
### 4. Run Checks
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npx threadlines check
|
|
50
|
+
```
|
|
51
|
+
|
|
17
52
|
## Usage
|
|
18
53
|
|
|
54
|
+
### Initialize Threadline Template
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
threadlines init
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Creates a template threadline file to get you started. The command will:
|
|
61
|
+
- Create the `/threadlines` directory if it doesn't exist
|
|
62
|
+
- Generate `threadlines/example.md` with boilerplate content
|
|
63
|
+
- Display instructions for API key configuration
|
|
64
|
+
|
|
65
|
+
### Check Code Against Threadlines
|
|
66
|
+
|
|
19
67
|
```bash
|
|
20
68
|
threadlines check
|
|
21
69
|
```
|
|
22
70
|
|
|
71
|
+
Analyzes your git changes against all threadlines in the `/threadlines` directory.
|
|
72
|
+
|
|
73
|
+
**Options:**
|
|
74
|
+
- `--api-url <url>` - Override the server URL (default: http://localhost:3000)
|
|
75
|
+
|
|
23
76
|
## Configuration
|
|
24
|
-
|
|
77
|
+
|
|
78
|
+
### Environment Variables
|
|
79
|
+
|
|
80
|
+
- `THREADLINE_API_KEY` - **Required.** Your Threadline API key for authentication
|
|
81
|
+
- Can be set in `.env.local` file (recommended for local development)
|
|
82
|
+
- Or as an environment variable (required for CI/CD)
|
|
25
83
|
- `THREADLINE_API_URL` - Server URL (default: http://localhost:3000)
|
|
26
84
|
- Can also be set with `--api-url` flag: `npx threadlines check --api-url http://your-server.com`
|
|
27
85
|
|
package/dist/commands/check.js
CHANGED
|
@@ -40,12 +40,26 @@ exports.checkCommand = checkCommand;
|
|
|
40
40
|
const experts_1 = require("../validators/experts");
|
|
41
41
|
const diff_1 = require("../git/diff");
|
|
42
42
|
const client_1 = require("../api/client");
|
|
43
|
+
const config_1 = require("../utils/config");
|
|
43
44
|
const fs = __importStar(require("fs"));
|
|
44
45
|
const path = __importStar(require("path"));
|
|
45
46
|
const chalk_1 = __importDefault(require("chalk"));
|
|
46
47
|
async function checkCommand(options) {
|
|
47
48
|
const repoRoot = process.cwd();
|
|
48
49
|
console.log(chalk_1.default.blue('🔍 Threadline: Checking code against your threadlines...\n'));
|
|
50
|
+
// Get and validate API key
|
|
51
|
+
const apiKey = (0, config_1.getThreadlineApiKey)();
|
|
52
|
+
if (!apiKey) {
|
|
53
|
+
console.error(chalk_1.default.red('❌ Error: THREADLINE_API_KEY is required'));
|
|
54
|
+
console.log('');
|
|
55
|
+
console.log(chalk_1.default.yellow('To fix this:'));
|
|
56
|
+
console.log(chalk_1.default.white(' 1. Create a .env.local file in your project root'));
|
|
57
|
+
console.log(chalk_1.default.gray(' 2. Add: THREADLINE_API_KEY=your-api-key-here'));
|
|
58
|
+
console.log(chalk_1.default.gray(' 3. Make sure .env.local is in your .gitignore'));
|
|
59
|
+
console.log('');
|
|
60
|
+
console.log(chalk_1.default.gray('For CI/CD: Set THREADLINE_API_KEY as an environment variable in your platform settings.'));
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
49
63
|
try {
|
|
50
64
|
// 1. Find and validate threadlines
|
|
51
65
|
console.log(chalk_1.default.gray('📋 Finding threadlines...'));
|
|
@@ -92,7 +106,8 @@ async function checkCommand(options) {
|
|
|
92
106
|
const response = await client.review({
|
|
93
107
|
threadlines: threadlinesWithContext,
|
|
94
108
|
diff: gitDiff.diff,
|
|
95
|
-
files: gitDiff.changedFiles
|
|
109
|
+
files: gitDiff.changedFiles,
|
|
110
|
+
apiKey
|
|
96
111
|
});
|
|
97
112
|
// 6. Display results
|
|
98
113
|
displayResults(response);
|
package/dist/commands/init.js
CHANGED
|
@@ -94,6 +94,15 @@ async function initCommand() {
|
|
|
94
94
|
console.log(chalk_1.default.blue('Next steps:'));
|
|
95
95
|
console.log(chalk_1.default.gray(' 1. Edit threadlines/example.md with your coding standards'));
|
|
96
96
|
console.log(chalk_1.default.gray(' 2. Rename it to something descriptive (e.g., error-handling.md)'));
|
|
97
|
+
console.log('');
|
|
98
|
+
console.log(chalk_1.default.yellow('⚠️ IMPORTANT: API Key Setup Required'));
|
|
99
|
+
console.log(chalk_1.default.white(' To use threadlines check, you need a THREADLINE_API_KEY.'));
|
|
100
|
+
console.log('');
|
|
101
|
+
console.log(chalk_1.default.white(' Create a .env.local file in your project root with:'));
|
|
102
|
+
console.log(chalk_1.default.gray(' THREADLINE_API_KEY=your-api-key-here'));
|
|
103
|
+
console.log('');
|
|
104
|
+
console.log(chalk_1.default.white(' Make sure .env.local is in your .gitignore file!'));
|
|
105
|
+
console.log('');
|
|
97
106
|
console.log(chalk_1.default.gray(' 3. Run: npx threadlines check'));
|
|
98
107
|
}
|
|
99
108
|
catch (error) {
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,51 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
|
+
};
|
|
3
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
// Load .env.local from project root before anything else
|
|
41
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const projectRoot = process.cwd();
|
|
45
|
+
const envLocalPath = path.join(projectRoot, '.env.local');
|
|
46
|
+
if (fs.existsSync(envLocalPath)) {
|
|
47
|
+
dotenv_1.default.config({ path: envLocalPath });
|
|
48
|
+
}
|
|
4
49
|
const commander_1 = require("commander");
|
|
5
50
|
const check_1 = require("./commands/check");
|
|
6
51
|
const init_1 = require("./commands/init");
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.getThreadlineApiKey = getThreadlineApiKey;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
43
|
+
/**
|
|
44
|
+
* Loads environment variables from .env.local file in the project root
|
|
45
|
+
* (where the user runs the command, not the CLI package directory)
|
|
46
|
+
*/
|
|
47
|
+
function loadEnvLocal() {
|
|
48
|
+
const projectRoot = process.cwd();
|
|
49
|
+
const envLocalPath = path.join(projectRoot, '.env.local');
|
|
50
|
+
if (fs.existsSync(envLocalPath)) {
|
|
51
|
+
dotenv_1.default.config({ path: envLocalPath });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Gets THREADLINE_API_KEY from environment.
|
|
56
|
+
* Priority: process.env.THREADLINE_API_KEY → .env.local file
|
|
57
|
+
*/
|
|
58
|
+
function getThreadlineApiKey() {
|
|
59
|
+
// Load .env.local if it exists (doesn't override existing env vars)
|
|
60
|
+
loadEnvLocal();
|
|
61
|
+
// Check environment variable (from shell or CI/CD)
|
|
62
|
+
return process.env.THREADLINE_API_KEY;
|
|
63
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "threadlines",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Threadline CLI - AI-powered linter based on your natural language documentation",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"repository": {
|
|
25
25
|
"type": "git",
|
|
26
|
-
"url": "https://github.com/ngrootscholten/threadline.git",
|
|
26
|
+
"url": "git+https://github.com/ngrootscholten/threadline.git",
|
|
27
27
|
"directory": "packages/cli"
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"commander": "^12.1.0",
|
|
37
|
+
"dotenv": "^16.4.7",
|
|
37
38
|
"simple-git": "^3.27.0",
|
|
38
39
|
"axios": "^1.7.9",
|
|
39
40
|
"chalk": "^4.1.2",
|