@yegor256/jinka 0.0.7 → 0.0.8
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/bin/jinka.js +9 -1
- package/package.json +1 -1
- package/src/semaphore.js +21 -0
package/bin/jinka.js
CHANGED
|
@@ -32,6 +32,7 @@ import { Crew } from '../src/crew.js';
|
|
|
32
32
|
import { Jobs } from '../src/jobs.js';
|
|
33
33
|
import { Summary } from '../src/summary.js';
|
|
34
34
|
import { Summarized } from '../src/summarized.js';
|
|
35
|
+
import { Semaphore } from '../src/semaphore.js';
|
|
35
36
|
|
|
36
37
|
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
37
38
|
const pkg = JSON.parse(await readFile(join(root, 'package.json'), 'utf8'));
|
|
@@ -63,7 +64,7 @@ const program = new Command()
|
|
|
63
64
|
.version(pkg.version)
|
|
64
65
|
.showHelpAfterError('(add --help for additional information)')
|
|
65
66
|
.addOption(new Option('--wishes <dir>', 'directory with wishes, one per Markdown file').default(join(homedir(), '.jinka', 'wishes'), '~/.jinka/wishes'))
|
|
66
|
-
.option('--threads <n>', `how many wishes run at once, up to ${limit}, which the + and - keys change while running`, bounded,
|
|
67
|
+
.option('--threads <n>', `how many wishes run at once, up to ${limit}, which the + and - keys change while running`, bounded, 6)
|
|
67
68
|
.addOption(new Option('--archive <dir>', 'directory where finished wishes are moved instead of being deleted').default(join(homedir(), '.jinka', 'archive'), '~/.jinka/archive'))
|
|
68
69
|
.addOption(new Option('--logs <dir>', 'directory where the output of every agent run is saved').default(join(homedir(), '.jinka', 'logs'), '~/.jinka/logs'))
|
|
69
70
|
.addOption(new Option('--memory <dir>', 'directory where agents keep what they learn about repositories between runs').default(join(homedir(), '.jinka', 'memory'), '~/.jinka/memory'))
|
|
@@ -75,9 +76,16 @@ const program = new Command()
|
|
|
75
76
|
.addOption(new Option('--model <name>', 'model passed to the agent').default('', 'agent default'))
|
|
76
77
|
.addOption(new Option('--effort <level>', 'reasoning effort passed to the agent, such as low, medium, high, xhigh, or max').default('', 'agent default'))
|
|
77
78
|
.option('--throttle <percent>', 'how much of the agent quota, in percent, must be left in every window before a new job starts', percent, 15)
|
|
79
|
+
.addOption(new Option('--pid <file>', 'file that exists while jinka runs, so that a second jinka refuses to start').default(join(homedir(), '.jinka', 'pid.txt'), '~/.jinka/pid.txt'))
|
|
78
80
|
.addOption(new Option('--limit <n>', 'how many jobs start before jinka waits for them to finish and quits').argParser(positive).default(Infinity, 'unlimited'))
|
|
79
81
|
.parse();
|
|
80
82
|
const values = program.opts();
|
|
83
|
+
const semaphore = new Semaphore(resolve(values.pid));
|
|
84
|
+
await semaphore.acquire().catch((e) => {
|
|
85
|
+
console.error(e.message);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
});
|
|
88
|
+
process.on('exit', () => semaphore.release());
|
|
81
89
|
const dir = resolve(values.wishes);
|
|
82
90
|
const engine = values.engine ?? (parse(values.agent).name === 'codex' ? 'codex' : 'claude');
|
|
83
91
|
const agent = values.agent === '' ? engine : values.agent;
|
package/package.json
CHANGED
package/src/semaphore.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright (c) 2026 Yegor Bugayenko
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
import { rmSync } from 'node:fs';
|
|
5
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
6
|
+
import { dirname } from 'node:path';
|
|
7
|
+
|
|
8
|
+
export class Semaphore {
|
|
9
|
+
constructor(file) {
|
|
10
|
+
this.file = file;
|
|
11
|
+
}
|
|
12
|
+
async acquire() {
|
|
13
|
+
await mkdir(dirname(this.file), { recursive: true });
|
|
14
|
+
await writeFile(this.file, String(process.pid), { flag: 'wx' }).catch((e) => {
|
|
15
|
+
throw e.code === 'EEXIST' ? new Error(`Another jinka is running, because the file ${this.file} already exists`) : e;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
release() {
|
|
19
|
+
rmSync(this.file, { force: true });
|
|
20
|
+
}
|
|
21
|
+
}
|