@pithyjs/codex 0.1.0-beta.0
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/LICENSE +21 -0
- package/README.md +4401 -0
- package/dist/annotations.d.ts +106 -0
- package/dist/annotations.js +306 -0
- package/dist/apply.d.ts +2 -0
- package/dist/apply.js +80 -0
- package/dist/changed-scope.d.ts +23 -0
- package/dist/changed-scope.js +31 -0
- package/dist/check.d.ts +2 -0
- package/dist/check.js +117 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +67 -0
- package/dist/env.d.ts +5 -0
- package/dist/env.js +35 -0
- package/dist/extract-cli.d.ts +23 -0
- package/dist/extract-cli.js +192 -0
- package/dist/extraction/breaking-changes.d.ts +66 -0
- package/dist/extraction/breaking-changes.js +352 -0
- package/dist/extraction/example-extractor.d.ts +55 -0
- package/dist/extraction/example-extractor.js +272 -0
- package/dist/extraction/index.d.ts +27 -0
- package/dist/extraction/index.js +31 -0
- package/dist/extraction/jsdoc-parser.d.ts +43 -0
- package/dist/extraction/jsdoc-parser.js +274 -0
- package/dist/extraction/pipeline.d.ts +54 -0
- package/dist/extraction/pipeline.js +526 -0
- package/dist/extraction/readme-sync.d.ts +108 -0
- package/dist/extraction/readme-sync.js +592 -0
- package/dist/extraction/snapshot-store.d.ts +40 -0
- package/dist/extraction/snapshot-store.js +153 -0
- package/dist/extraction/source-linker.d.ts +80 -0
- package/dist/extraction/source-linker.js +316 -0
- package/dist/extraction/test-example-extractor.d.ts +69 -0
- package/dist/extraction/test-example-extractor.js +400 -0
- package/dist/extraction/test-pattern-extractor.d.ts +68 -0
- package/dist/extraction/test-pattern-extractor.js +261 -0
- package/dist/extraction/testing-pyramid.d.ts +44 -0
- package/dist/extraction/testing-pyramid.js +163 -0
- package/dist/extraction/type-extractor.d.ts +34 -0
- package/dist/extraction/type-extractor.js +494 -0
- package/dist/extraction/types.d.ts +401 -0
- package/dist/extraction/types.js +34 -0
- package/dist/indexer.d.ts +1 -0
- package/dist/indexer.js +107 -0
- package/dist/llm.d.ts +8 -0
- package/dist/llm.js +75 -0
- package/dist/readme-sync-cli.d.ts +20 -0
- package/dist/readme-sync-cli.js +167 -0
- package/dist/review.d.ts +2 -0
- package/dist/review.js +93 -0
- package/dist/scan.d.ts +29 -0
- package/dist/scan.js +221 -0
- package/dist/schema.d.ts +169 -0
- package/dist/schema.js +70 -0
- package/dist/snapshot-cli.d.ts +45 -0
- package/dist/snapshot-cli.js +217 -0
- package/dist/sync-cli.d.ts +22 -0
- package/dist/sync-cli.js +154 -0
- package/dist/sync-pipeline.d.ts +58 -0
- package/dist/sync-pipeline.js +104 -0
- package/dist/sync.d.ts +2 -0
- package/dist/sync.js +318 -0
- package/dist/validate-cli.d.ts +20 -0
- package/dist/validate-cli.js +144 -0
- package/dist/validate.d.ts +76 -0
- package/dist/validate.js +183 -0
- package/dist/watch-cli.d.ts +21 -0
- package/dist/watch-cli.js +220 -0
- package/package.json +62 -0
package/dist/validate.js
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @codex
|
|
3
|
+
* {
|
|
4
|
+
* "id": "pithy.codex.validate",
|
|
5
|
+
* "title": "Documentation Validator",
|
|
6
|
+
* "category": "feature"
|
|
7
|
+
* }
|
|
8
|
+
*
|
|
9
|
+
* Validates extracted documentation examples by checking they are
|
|
10
|
+
* syntactically valid TypeScript. Used by `pnpm codex validate` and CI drift checks.
|
|
11
|
+
*/
|
|
12
|
+
import ts from 'typescript';
|
|
13
|
+
/**
|
|
14
|
+
* Languages we can validate syntactically
|
|
15
|
+
*/
|
|
16
|
+
const VALIDATABLE_LANGUAGES = new Set(['typescript', 'ts', 'javascript', 'js']);
|
|
17
|
+
/**
|
|
18
|
+
* @codexApi {"parent":"pithy.codex.validate","name":"validateExampleSyntax","stability":"stable","signature":"(code: string, componentId?: string, apiName?: string, language?: string) => ExampleValidationResult"}
|
|
19
|
+
*
|
|
20
|
+
* Validates a single code example for syntactic correctness using TypeScript compiler.
|
|
21
|
+
* Does NOT type-check ā only parses for syntax errors.
|
|
22
|
+
*
|
|
23
|
+
* @param code - The example code to validate
|
|
24
|
+
* @param componentId - The ID of the component the example belongs to (default: "")
|
|
25
|
+
* @param apiName - The name of the API the example belongs to
|
|
26
|
+
* @param language - The language of the example (default: "typescript")
|
|
27
|
+
* @returns Validation result with diagnostics if invalid
|
|
28
|
+
*/
|
|
29
|
+
export function validateExampleSyntax(code, componentId = '', apiName, language = 'typescript') {
|
|
30
|
+
const lang = language.toLowerCase();
|
|
31
|
+
if (!VALIDATABLE_LANGUAGES.has(lang)) {
|
|
32
|
+
return {
|
|
33
|
+
code,
|
|
34
|
+
componentId,
|
|
35
|
+
apiName,
|
|
36
|
+
valid: true,
|
|
37
|
+
diagnostics: [],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const isJs = lang === 'javascript' || lang === 'js';
|
|
41
|
+
const fileName = isJs ? 'example.js' : 'example.ts';
|
|
42
|
+
const scriptKind = isJs ? ts.ScriptKind.JS : ts.ScriptKind.TS;
|
|
43
|
+
const sourceFile = ts.createSourceFile(fileName, code, ts.ScriptTarget.Latest, true, scriptKind);
|
|
44
|
+
// Collect parse diagnostics (syntax errors only)
|
|
45
|
+
const diagnostics = [];
|
|
46
|
+
// TypeScript's createSourceFile doesn't expose parseDiagnostics directly,
|
|
47
|
+
// so we use a minimal compiler host for syntax-only check
|
|
48
|
+
const compilerOptions = {
|
|
49
|
+
noEmit: true,
|
|
50
|
+
allowJs: true,
|
|
51
|
+
target: ts.ScriptTarget.Latest,
|
|
52
|
+
module: ts.ModuleKind.ESNext,
|
|
53
|
+
moduleResolution: ts.ModuleResolutionKind.Bundler,
|
|
54
|
+
// Loose settings ā we only care about syntax, not type errors
|
|
55
|
+
strict: false,
|
|
56
|
+
noImplicitAny: false,
|
|
57
|
+
skipLibCheck: true,
|
|
58
|
+
};
|
|
59
|
+
const host = ts.createCompilerHost(compilerOptions);
|
|
60
|
+
const originalGetSourceFile = host.getSourceFile;
|
|
61
|
+
host.getSourceFile = (fileName, languageVersion) => {
|
|
62
|
+
if (fileName === sourceFile.fileName) {
|
|
63
|
+
return sourceFile;
|
|
64
|
+
}
|
|
65
|
+
return originalGetSourceFile.call(host, fileName, languageVersion);
|
|
66
|
+
};
|
|
67
|
+
host.fileExists = fileName => fileName === sourceFile.fileName || ts.sys.fileExists(fileName);
|
|
68
|
+
host.readFile = fileName => fileName === sourceFile.fileName ? code : ts.sys.readFile(fileName);
|
|
69
|
+
const program = ts.createProgram([sourceFile.fileName], compilerOptions, host);
|
|
70
|
+
// Only get syntactic diagnostics (parse errors), not semantic
|
|
71
|
+
const syntacticDiags = program.getSyntacticDiagnostics(sourceFile);
|
|
72
|
+
for (const diag of syntacticDiags) {
|
|
73
|
+
const message = ts.flattenDiagnosticMessageText(diag.messageText, '\n');
|
|
74
|
+
const line = diag.file && diag.start !== undefined
|
|
75
|
+
? diag.file.getLineAndCharacterOfPosition(diag.start).line + 1
|
|
76
|
+
: 0;
|
|
77
|
+
diagnostics.push(`Line ${line}: ${message}`);
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
code,
|
|
81
|
+
componentId,
|
|
82
|
+
apiName,
|
|
83
|
+
valid: diagnostics.length === 0,
|
|
84
|
+
diagnostics,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* @codexApi {"parent":"pithy.codex.validate","name":"validateExtractionResult","stability":"stable","signature":"(result: ExtendedExtractionResult) => ValidationResult"}
|
|
89
|
+
*
|
|
90
|
+
* Validates all extracted examples from an extraction pipeline result.
|
|
91
|
+
* Checks that TypeScript/JavaScript examples are syntactically valid.
|
|
92
|
+
*
|
|
93
|
+
* @param result - The extraction result to validate
|
|
94
|
+
* @returns Aggregate validation result
|
|
95
|
+
*/
|
|
96
|
+
export function validateExtractionResult(result) {
|
|
97
|
+
const startTime = performance.now();
|
|
98
|
+
const invalidExamples = [];
|
|
99
|
+
let totalExamples = 0;
|
|
100
|
+
let validCount = 0;
|
|
101
|
+
let invalidCount = 0;
|
|
102
|
+
let skippedCount = 0;
|
|
103
|
+
for (const component of result.components) {
|
|
104
|
+
// Validate component-level examples
|
|
105
|
+
for (const example of component.examples) {
|
|
106
|
+
totalExamples++;
|
|
107
|
+
if (!VALIDATABLE_LANGUAGES.has(example.language.toLowerCase())) {
|
|
108
|
+
skippedCount++;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const validation = validateExampleSyntax(example.code, component.id, undefined, example.language);
|
|
112
|
+
if (validation.valid) {
|
|
113
|
+
validCount++;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
invalidCount++;
|
|
117
|
+
invalidExamples.push(validation);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Validate API-level examples
|
|
121
|
+
for (const api of component.apis) {
|
|
122
|
+
for (const example of api.examples) {
|
|
123
|
+
totalExamples++;
|
|
124
|
+
if (!VALIDATABLE_LANGUAGES.has(example.language.toLowerCase())) {
|
|
125
|
+
skippedCount++;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const validation = validateExampleSyntax(example.code, component.id, api.name, example.language);
|
|
129
|
+
if (validation.valid) {
|
|
130
|
+
validCount++;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
invalidCount++;
|
|
134
|
+
invalidExamples.push(validation);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
totalExamples,
|
|
141
|
+
validCount,
|
|
142
|
+
invalidCount,
|
|
143
|
+
skippedCount,
|
|
144
|
+
invalidExamples,
|
|
145
|
+
totalTimeMs: performance.now() - startTime,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* @codexApi {"parent":"pithy.codex.validate","name":"formatValidationReport","stability":"stable","signature":"(result: ValidationResult) => string"}
|
|
150
|
+
*
|
|
151
|
+
* Formats a human-readable validation report.
|
|
152
|
+
*
|
|
153
|
+
* @param result - Validation result to format
|
|
154
|
+
* @returns Formatted report string
|
|
155
|
+
*/
|
|
156
|
+
export function formatValidationReport(result) {
|
|
157
|
+
const lines = [
|
|
158
|
+
'š Example Validation Report',
|
|
159
|
+
'',
|
|
160
|
+
`Total examples: ${result.totalExamples}`,
|
|
161
|
+
` ā
Valid: ${result.validCount}`,
|
|
162
|
+
` ā Invalid: ${result.invalidCount}`,
|
|
163
|
+
` ā Skipped: ${result.skippedCount}`,
|
|
164
|
+
` ā± Time: ${result.totalTimeMs.toFixed(0)}ms`,
|
|
165
|
+
];
|
|
166
|
+
if (result.invalidExamples.length > 0) {
|
|
167
|
+
lines.push('');
|
|
168
|
+
lines.push('Invalid Examples:');
|
|
169
|
+
for (const ex of result.invalidExamples) {
|
|
170
|
+
const location = ex.apiName
|
|
171
|
+
? `${ex.componentId}.${ex.apiName}`
|
|
172
|
+
: ex.componentId;
|
|
173
|
+
lines.push(`\n āā ${location} āā`);
|
|
174
|
+
const firstLine = ex.code.split('\n')[0] || '';
|
|
175
|
+
const preview = firstLine.length > 80 ? firstLine.slice(0, 77) + '...' : firstLine;
|
|
176
|
+
lines.push(` Code: ${preview}`);
|
|
177
|
+
for (const diag of ex.diagnostics) {
|
|
178
|
+
lines.push(` ${diag}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return lines.join('\n');
|
|
183
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @codex
|
|
4
|
+
* {
|
|
5
|
+
* "id": "pithy.codex.watch-cli",
|
|
6
|
+
* "title": "Watch CLI",
|
|
7
|
+
* "category": "plugin"
|
|
8
|
+
* }
|
|
9
|
+
*
|
|
10
|
+
* Watch mode for codex sync. Monitors source files for changes and
|
|
11
|
+
* re-runs the sync pipeline automatically.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* pnpm codex watch [options]
|
|
15
|
+
*
|
|
16
|
+
* Options:
|
|
17
|
+
* --root <path> Project root directory (default: cwd)
|
|
18
|
+
* --debounce <ms> Debounce interval in milliseconds (default: 300)
|
|
19
|
+
* --verbose Show detailed progress
|
|
20
|
+
*/
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @codex
|
|
4
|
+
* {
|
|
5
|
+
* "id": "pithy.codex.watch-cli",
|
|
6
|
+
* "title": "Watch CLI",
|
|
7
|
+
* "category": "plugin"
|
|
8
|
+
* }
|
|
9
|
+
*
|
|
10
|
+
* Watch mode for codex sync. Monitors source files for changes and
|
|
11
|
+
* re-runs the sync pipeline automatically.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* pnpm codex watch [options]
|
|
15
|
+
*
|
|
16
|
+
* Options:
|
|
17
|
+
* --root <path> Project root directory (default: cwd)
|
|
18
|
+
* --debounce <ms> Debounce interval in milliseconds (default: 300)
|
|
19
|
+
* --verbose Show detailed progress
|
|
20
|
+
*/
|
|
21
|
+
import { resolve, relative } from 'node:path';
|
|
22
|
+
import fs from 'node:fs/promises';
|
|
23
|
+
import { watch } from 'node:fs';
|
|
24
|
+
import { runSyncPipeline } from './sync-pipeline.js';
|
|
25
|
+
function parseArgs(args) {
|
|
26
|
+
const options = {
|
|
27
|
+
root: process.cwd(),
|
|
28
|
+
debounceMs: 300,
|
|
29
|
+
verbose: false,
|
|
30
|
+
};
|
|
31
|
+
for (let i = 0; i < args.length; i++) {
|
|
32
|
+
const arg = args[i];
|
|
33
|
+
if (arg.startsWith('--root=')) {
|
|
34
|
+
options.root = arg.slice('--root='.length);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
switch (arg) {
|
|
38
|
+
case '--root': {
|
|
39
|
+
const next = args[i + 1];
|
|
40
|
+
if (!next || next.startsWith('-')) {
|
|
41
|
+
console.error('Error: --root option requires a path argument.');
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
options.root = next;
|
|
45
|
+
i++;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
case '--debounce': {
|
|
49
|
+
const next = args[i + 1];
|
|
50
|
+
if (!next || isNaN(Number(next))) {
|
|
51
|
+
console.error('Error: --debounce option requires a number in milliseconds.');
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
options.debounceMs = Number(next);
|
|
55
|
+
i++;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
case '--verbose':
|
|
59
|
+
case '-v':
|
|
60
|
+
options.verbose = true;
|
|
61
|
+
break;
|
|
62
|
+
case '--help':
|
|
63
|
+
case '-h':
|
|
64
|
+
printHelp();
|
|
65
|
+
process.exit(0);
|
|
66
|
+
break;
|
|
67
|
+
default:
|
|
68
|
+
if (arg.startsWith('-')) {
|
|
69
|
+
console.warn(`Warning: unknown option "${arg}" (ignored)`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return options;
|
|
74
|
+
}
|
|
75
|
+
function printHelp() {
|
|
76
|
+
console.log(`
|
|
77
|
+
Codex Watch
|
|
78
|
+
|
|
79
|
+
Watches for source file changes and re-runs the sync pipeline automatically.
|
|
80
|
+
Monitors TypeScript (.ts), JavaScript (.js), and README files in the packages/ directory.
|
|
81
|
+
|
|
82
|
+
Usage:
|
|
83
|
+
pithy-codex-watch [options]
|
|
84
|
+
pnpm --filter @pithyjs/codex watch [-- options]
|
|
85
|
+
|
|
86
|
+
Options:
|
|
87
|
+
--root <path> Project root directory (default: current directory)
|
|
88
|
+
--debounce <ms> Debounce interval in milliseconds (default: 300)
|
|
89
|
+
--verbose, -v Show detailed progress
|
|
90
|
+
--help, -h Show this help message
|
|
91
|
+
|
|
92
|
+
Examples:
|
|
93
|
+
# Watch from project root
|
|
94
|
+
pithy-codex-watch --root ../..
|
|
95
|
+
|
|
96
|
+
# Watch with longer debounce
|
|
97
|
+
pithy-codex-watch --root ../.. --debounce 1000 --verbose
|
|
98
|
+
`);
|
|
99
|
+
}
|
|
100
|
+
/** Directories to watch within the root */
|
|
101
|
+
const WATCH_DIRS = ['packages'];
|
|
102
|
+
/** File patterns to trigger re-sync */
|
|
103
|
+
function shouldTriggerSync(filename) {
|
|
104
|
+
if (!filename)
|
|
105
|
+
return false;
|
|
106
|
+
return (filename.endsWith('.ts') ||
|
|
107
|
+
filename.endsWith('.js') ||
|
|
108
|
+
/README(?:\.md)?$/i.test(filename));
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Creates a debounced function that delays invoking func until after
|
|
112
|
+
* wait milliseconds have elapsed since the last time it was invoked.
|
|
113
|
+
*/
|
|
114
|
+
function debounce(func, wait) {
|
|
115
|
+
let timeoutId = null;
|
|
116
|
+
return (...args) => {
|
|
117
|
+
if (timeoutId !== null) {
|
|
118
|
+
clearTimeout(timeoutId);
|
|
119
|
+
}
|
|
120
|
+
timeoutId = setTimeout(() => {
|
|
121
|
+
timeoutId = null;
|
|
122
|
+
func(...args);
|
|
123
|
+
}, wait);
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
async function main() {
|
|
127
|
+
const args = process.argv.slice(2);
|
|
128
|
+
const options = parseArgs(args);
|
|
129
|
+
options.root = resolve(options.root);
|
|
130
|
+
// Verify root exists
|
|
131
|
+
try {
|
|
132
|
+
const stat = await fs.stat(options.root);
|
|
133
|
+
if (!stat.isDirectory()) {
|
|
134
|
+
console.error(`ā Error: "${options.root}" is not a directory`);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
console.error(`ā Error: Root directory "${options.root}" does not exist`);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
const logger = {
|
|
143
|
+
log: msg => console.log(msg),
|
|
144
|
+
warn: msg => console.warn(msg),
|
|
145
|
+
error: msg => console.error(msg),
|
|
146
|
+
};
|
|
147
|
+
let running = false;
|
|
148
|
+
const runSync = async () => {
|
|
149
|
+
if (running)
|
|
150
|
+
return;
|
|
151
|
+
running = true;
|
|
152
|
+
console.log('\nš Change detected ā re-syncing...\n');
|
|
153
|
+
try {
|
|
154
|
+
await runSyncPipeline({
|
|
155
|
+
root: options.root,
|
|
156
|
+
verbose: options.verbose,
|
|
157
|
+
}, logger);
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
console.error('ā Sync failed:', error instanceof Error ? error.message : error);
|
|
161
|
+
}
|
|
162
|
+
running = false;
|
|
163
|
+
};
|
|
164
|
+
const debouncedSync = debounce(runSync, options.debounceMs);
|
|
165
|
+
// Initial sync
|
|
166
|
+
console.log('š Codex Watch Mode');
|
|
167
|
+
console.log(` Root: ${options.root}`);
|
|
168
|
+
console.log(` Debounce: ${options.debounceMs}ms`);
|
|
169
|
+
console.log('');
|
|
170
|
+
console.log('Running initial sync...');
|
|
171
|
+
await runSync();
|
|
172
|
+
// Set up file watchers
|
|
173
|
+
const activeWatchers = [];
|
|
174
|
+
const watchDirs = [];
|
|
175
|
+
for (const dir of WATCH_DIRS) {
|
|
176
|
+
const fullDir = resolve(options.root, dir);
|
|
177
|
+
try {
|
|
178
|
+
await fs.stat(fullDir);
|
|
179
|
+
watchDirs.push(fullDir);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// Directory doesn't exist, skip
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (watchDirs.length === 0) {
|
|
186
|
+
console.error('ā No watch directories found');
|
|
187
|
+
process.exit(1);
|
|
188
|
+
}
|
|
189
|
+
for (const dir of watchDirs) {
|
|
190
|
+
// Note: { recursive: true } is supported on Windows and macOS.
|
|
191
|
+
// On Linux, consider using chokidar for recursive watching.
|
|
192
|
+
const watcher = watch(dir, { recursive: true }, (_event, filename) => {
|
|
193
|
+
if (filename && shouldTriggerSync(filename)) {
|
|
194
|
+
if (options.verbose) {
|
|
195
|
+
console.log(` š ${relative(options.root, resolve(dir, filename))}`);
|
|
196
|
+
}
|
|
197
|
+
debouncedSync();
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
watcher.on('error', err => {
|
|
201
|
+
console.error(`Watch error on ${dir}:`, err.message);
|
|
202
|
+
});
|
|
203
|
+
activeWatchers.push(watcher);
|
|
204
|
+
console.log(` Watching: ${relative(options.root, dir)}/`);
|
|
205
|
+
}
|
|
206
|
+
// Cleanup on exit
|
|
207
|
+
process.on('SIGINT', () => {
|
|
208
|
+
for (const w of activeWatchers) {
|
|
209
|
+
w.close();
|
|
210
|
+
}
|
|
211
|
+
console.log('\nš Watch stopped');
|
|
212
|
+
process.exit(0);
|
|
213
|
+
});
|
|
214
|
+
console.log('');
|
|
215
|
+
console.log('Waiting for changes... (Ctrl+C to stop)');
|
|
216
|
+
}
|
|
217
|
+
main().catch(err => {
|
|
218
|
+
console.error('Fatal error:', err);
|
|
219
|
+
process.exit(1);
|
|
220
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pithyjs/codex",
|
|
3
|
+
"version": "0.1.0-beta.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/cli.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./dist/cli.js",
|
|
8
|
+
"./extraction": "./dist/extraction/index.js"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"pithy-codex": "dist/cli.js",
|
|
12
|
+
"pithy-codex-check": "dist/check.js",
|
|
13
|
+
"pithy-codex-index": "dist/indexer.js",
|
|
14
|
+
"pithy-codex-extract": "dist/extract-cli.js",
|
|
15
|
+
"pithy-codex-readme-sync": "dist/readme-sync-cli.js",
|
|
16
|
+
"pithy-codex-sync": "dist/sync-cli.js",
|
|
17
|
+
"pithy-codex-validate": "dist/validate-cli.js",
|
|
18
|
+
"pithy-codex-watch": "dist/watch-cli.js",
|
|
19
|
+
"pithy-codex-snapshot": "dist/snapshot-cli.js"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"dotenv": "^17.2.1",
|
|
23
|
+
"execa": "^9.6.0",
|
|
24
|
+
"globby": "^14.1.0",
|
|
25
|
+
"openai": "^5.12.2",
|
|
26
|
+
"simple-git": "^3.28.0",
|
|
27
|
+
"typescript": "^5.8.3",
|
|
28
|
+
"zod": "^3.24.4"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^22",
|
|
32
|
+
"vitest": "3.2.4"
|
|
33
|
+
},
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsc -p tsconfig.json",
|
|
43
|
+
"test": "vitest run",
|
|
44
|
+
"test:watch": "vitest",
|
|
45
|
+
"sync": "node dist/sync.js --root ../../..",
|
|
46
|
+
"sync:direct": "node dist/sync.js --root ../../.. --no-llm --direct",
|
|
47
|
+
"sync:debug": "node dist/sync.js --root ../../.. --debug",
|
|
48
|
+
"sync:prompts": "node dist/sync.js --root ../../.. --emit-prompts --debug",
|
|
49
|
+
"sync-pipeline": "node dist/sync-cli.js",
|
|
50
|
+
"validate": "node dist/validate-cli.js",
|
|
51
|
+
"watch": "node dist/watch-cli.js",
|
|
52
|
+
"review": "node dist/review.js --root ../../..",
|
|
53
|
+
"apply": "node dist/apply.js --root ../../..",
|
|
54
|
+
"check": "node dist/check.js",
|
|
55
|
+
"index": "node dist/indexer.js",
|
|
56
|
+
"extract": "node dist/extract-cli.js --root ../..",
|
|
57
|
+
"readme-sync": "node dist/readme-sync-cli.js --root ../..",
|
|
58
|
+
"readme-sync:dry": "node dist/readme-sync-cli.js --root ../.. --dry-run --verbose",
|
|
59
|
+
"snapshot": "node dist/snapshot-cli.js --root ../..",
|
|
60
|
+
"gen": "pnpm -w --filter @pithyjs/codex sync && pnpm -w --filter @pithyjs/codex review && pnpm -w --filter @pithyjs/codex apply"
|
|
61
|
+
}
|
|
62
|
+
}
|