threadlines 0.1.1 → 0.1.3
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 +1 -1
- package/dist/commands/check.js +4 -8
- package/dist/commands/init.js +103 -0
- package/dist/index.js +7 -3
- package/dist/validators/experts.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ threadlines check
|
|
|
23
23
|
## Configuration
|
|
24
24
|
|
|
25
25
|
- `THREADLINE_API_URL` - Server URL (default: http://localhost:3000)
|
|
26
|
-
-
|
|
26
|
+
- Can also be set with `--api-url` flag: `npx threadlines check --api-url http://your-server.com`
|
|
27
27
|
|
|
28
28
|
## Threadline Files
|
|
29
29
|
|
package/dist/commands/check.js
CHANGED
|
@@ -52,7 +52,8 @@ async function checkCommand(options) {
|
|
|
52
52
|
const threadlines = await (0, experts_1.findThreadlines)(repoRoot);
|
|
53
53
|
console.log(chalk_1.default.green(`✓ Found ${threadlines.length} threadline(s)\n`));
|
|
54
54
|
if (threadlines.length === 0) {
|
|
55
|
-
console.log(chalk_1.default.yellow('⚠️ No valid threadlines found.
|
|
55
|
+
console.log(chalk_1.default.yellow('⚠️ No valid threadlines found.'));
|
|
56
|
+
console.log(chalk_1.default.gray(' Run `npx threadlines init` to create your first threadline.'));
|
|
56
57
|
process.exit(0);
|
|
57
58
|
}
|
|
58
59
|
// 2. Get git diff
|
|
@@ -83,20 +84,15 @@ async function checkCommand(options) {
|
|
|
83
84
|
contextContent
|
|
84
85
|
};
|
|
85
86
|
});
|
|
86
|
-
// 4. Get API URL
|
|
87
|
+
// 4. Get API URL
|
|
87
88
|
const apiUrl = options.apiUrl || process.env.THREADLINE_API_URL || 'http://localhost:3000';
|
|
88
|
-
const apiKey = options.apiKey || process.env.OPENAI_API_KEY;
|
|
89
|
-
if (!apiKey) {
|
|
90
|
-
throw new Error('OpenAI API key required. Set OPENAI_API_KEY environment variable.');
|
|
91
|
-
}
|
|
92
89
|
// 5. Call review API
|
|
93
90
|
console.log(chalk_1.default.gray('🤖 Running threadline checks...'));
|
|
94
91
|
const client = new client_1.ReviewAPIClient(apiUrl);
|
|
95
92
|
const response = await client.review({
|
|
96
93
|
threadlines: threadlinesWithContext,
|
|
97
94
|
diff: gitDiff.diff,
|
|
98
|
-
files: gitDiff.changedFiles
|
|
99
|
-
apiKey
|
|
95
|
+
files: gitDiff.changedFiles
|
|
100
96
|
});
|
|
101
97
|
// 6. Display results
|
|
102
98
|
displayResults(response);
|
|
@@ -0,0 +1,103 @@
|
|
|
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.initCommand = initCommand;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
43
|
+
const TEMPLATE = `---
|
|
44
|
+
id: example-threadline
|
|
45
|
+
version: 1.0.0
|
|
46
|
+
patterns:
|
|
47
|
+
- "**/*.ts"
|
|
48
|
+
- "**/*.tsx"
|
|
49
|
+
context_files: []
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
# Example Threadline
|
|
53
|
+
|
|
54
|
+
Describe your coding standard or convention here.
|
|
55
|
+
|
|
56
|
+
This threadline will check all TypeScript files (\`**/*.ts\` and \`**/*.tsx\`) against the guidelines you define below.
|
|
57
|
+
|
|
58
|
+
## Guidelines
|
|
59
|
+
|
|
60
|
+
- Add your first guideline here
|
|
61
|
+
- Add your second guideline here
|
|
62
|
+
- Add examples or patterns to follow
|
|
63
|
+
|
|
64
|
+
## Examples
|
|
65
|
+
|
|
66
|
+
\`\`\`typescript
|
|
67
|
+
// Good example
|
|
68
|
+
\`\`\`
|
|
69
|
+
|
|
70
|
+
\`\`\`typescript
|
|
71
|
+
// Bad example - avoid this
|
|
72
|
+
\`\`\`
|
|
73
|
+
`;
|
|
74
|
+
async function initCommand() {
|
|
75
|
+
const repoRoot = process.cwd();
|
|
76
|
+
const threadlinesDir = path.join(repoRoot, 'threadlines');
|
|
77
|
+
const exampleFile = path.join(threadlinesDir, 'example.md');
|
|
78
|
+
try {
|
|
79
|
+
// Create threadlines directory if it doesn't exist
|
|
80
|
+
if (!fs.existsSync(threadlinesDir)) {
|
|
81
|
+
fs.mkdirSync(threadlinesDir, { recursive: true });
|
|
82
|
+
console.log(chalk_1.default.green(`✓ Created /threadlines directory`));
|
|
83
|
+
}
|
|
84
|
+
// Check if example file already exists
|
|
85
|
+
if (fs.existsSync(exampleFile)) {
|
|
86
|
+
console.log(chalk_1.default.yellow(`⚠️ ${exampleFile} already exists`));
|
|
87
|
+
console.log(chalk_1.default.gray(' Edit it to create your threadline, or delete it and run init again.'));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
// Write template file
|
|
91
|
+
fs.writeFileSync(exampleFile, TEMPLATE, 'utf-8');
|
|
92
|
+
console.log(chalk_1.default.green(`✓ Created ${exampleFile}`));
|
|
93
|
+
console.log('');
|
|
94
|
+
console.log(chalk_1.default.blue('Next steps:'));
|
|
95
|
+
console.log(chalk_1.default.gray(' 1. Edit threadlines/example.md with your coding standards'));
|
|
96
|
+
console.log(chalk_1.default.gray(' 2. Rename it to something descriptive (e.g., error-handling.md)'));
|
|
97
|
+
console.log(chalk_1.default.gray(' 3. Run: npx threadlines check'));
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
console.error(chalk_1.default.red(`\n❌ Error: ${error.message}`));
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -3,15 +3,19 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const commander_1 = require("commander");
|
|
5
5
|
const check_1 = require("./commands/check");
|
|
6
|
+
const init_1 = require("./commands/init");
|
|
6
7
|
const program = new commander_1.Command();
|
|
7
8
|
program
|
|
8
|
-
.name('
|
|
9
|
+
.name('threadlines')
|
|
9
10
|
.description('AI-powered linter based on your natural language documentation')
|
|
10
11
|
.version('0.1.0');
|
|
12
|
+
program
|
|
13
|
+
.command('init')
|
|
14
|
+
.description('Create a template threadline file to get started')
|
|
15
|
+
.action(init_1.initCommand);
|
|
11
16
|
program
|
|
12
17
|
.command('check')
|
|
13
|
-
.description('Check code against your
|
|
18
|
+
.description('Check code against your threadlines')
|
|
14
19
|
.option('--api-url <url>', 'Threadline server URL', process.env.THREADLINE_API_URL || 'http://localhost:3000')
|
|
15
|
-
.option('--api-key <key>', 'OpenAI API key', process.env.OPENAI_API_KEY)
|
|
16
20
|
.action(check_1.checkCommand);
|
|
17
21
|
program.parse();
|
|
@@ -42,12 +42,12 @@ const REQUIRED_FIELDS = ['id', 'version', 'patterns'];
|
|
|
42
42
|
async function findThreadlines(repoRoot) {
|
|
43
43
|
const expertsDir = path.join(repoRoot, 'threadlines');
|
|
44
44
|
if (!fs.existsSync(expertsDir)) {
|
|
45
|
-
throw new Error('No /threadlines folder found.
|
|
45
|
+
throw new Error('No /threadlines folder found. Run `npx threadlines init` to create your first threadline.');
|
|
46
46
|
}
|
|
47
47
|
const files = fs.readdirSync(expertsDir);
|
|
48
48
|
const expertFiles = files.filter(f => f.endsWith('.md'));
|
|
49
49
|
if (expertFiles.length === 0) {
|
|
50
|
-
throw new Error('No threadline files found in /threadlines folder.
|
|
50
|
+
throw new Error('No threadline files found in /threadlines folder. Run `npx threadlines init` to create a template.');
|
|
51
51
|
}
|
|
52
52
|
const threadlines = [];
|
|
53
53
|
for (const file of expertFiles) {
|