zames_pro 2.54.0 → 2.58.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.
@@ -0,0 +1,83 @@
1
+ import { spawnSync } from 'node:child_process'
2
+
3
+ // Soft coverage FLOOR for the PURE logic modules — the ones a regression would
4
+ // silently break without any UI symptom (command formatting, schedule parsing,
5
+ // the raw SSE/model-answer parsing). The floors are deliberately a few points
6
+ // BELOW the current values so ordinary churn does not fail the build; they
7
+ // only catch a real drop (a module losing its tests).
8
+ //
9
+ // Node's test runner has no built-in coverage threshold, so we parse the
10
+ // per-file line % from the coverage report it prints and compare here. This is
11
+ // informational in the sense that the FLOORS are conservative, but a drop
12
+ // below one is a hard failure.
13
+ const FLOORS = {
14
+ 'commands.ts': 85,
15
+ 'scheduler.ts': 90,
16
+ 'net-capture.ts': 90,
17
+ 'xml-toolcall.ts': 90,
18
+ 'diff.ts': 90,
19
+ 'theme.ts': 95,
20
+ // Added later: core logic or already well-tested, so a silent regression
21
+ // that deletes their tests should be caught too. Floors sit a few points
22
+ // below the current values.
23
+ 'extraTools.ts': 85,
24
+ 'fsutil.ts': 90,
25
+ 'sessions.ts': 90,
26
+ 'context.ts': 85,
27
+ 'markdown.ts': 90,
28
+ 'tools.ts': 90,
29
+ 'system-prompt.ts': 90,
30
+ 'undo.ts': 85,
31
+ }
32
+
33
+ const run = spawnSync(
34
+ 'npx',
35
+ ['tsx', '--test', '--experimental-test-coverage', 'test/*.test.ts'],
36
+ { encoding: 'utf-8', shell: process.platform === 'win32', maxBuffer: 1024 * 1024 * 64 },
37
+ )
38
+
39
+ const out = (run.stdout || '') + (run.stderr || '')
40
+
41
+ if (run.status !== 0) {
42
+ console.error('coverage-gate: test run failed (exit ' + run.status + ')')
43
+ process.exit(1)
44
+ }
45
+
46
+ const linePct = new Map()
47
+ for (const line of out.split('\n')) {
48
+ // Per-file rows look like:
49
+ // ℹ commands.ts | 94.14 | 78.70 | 93.88 | 40-56 ...
50
+ const m = line.match(/^\s*\S?\s*([A-Za-z0-9._-]+\.ts)\s+\|\s+([\d.]+)\s+\|/)
51
+ if (m) linePct.set(m[1], Number(m[2]))
52
+ }
53
+
54
+ const failures = []
55
+ for (const [file, floor] of Object.entries(FLOORS)) {
56
+ const pct = linePct.get(file)
57
+ if (pct === undefined) {
58
+ failures.push(file + ': no coverage row found')
59
+ continue
60
+ }
61
+ if (pct < floor) {
62
+ failures.push(file + ': ' + pct + '% < floor ' + floor + '%')
63
+ } else {
64
+ console.log('coverage-gate: ' + file + ' ' + pct + '% >= ' + floor + '%')
65
+ }
66
+ }
67
+
68
+ // Print the lowest-covered modules, so a dead or untested module is visible
69
+ // in the CI log even when it has no floor yet. Informational only.
70
+ const sorted = [...linePct.entries()].sort((a, b) => a[1] - b[1]).slice(0, 8)
71
+ if (sorted.length) {
72
+ console.log('coverage-gate: lowest covered modules (informational):')
73
+ for (const [name, pct] of sorted) {
74
+ console.log(' ' + name + ' ' + pct + '%')
75
+ }
76
+ }
77
+
78
+ if (failures.length) {
79
+ console.error('coverage-gate: FAILED')
80
+ for (const f of failures) console.error(' ' + f)
81
+ process.exit(1)
82
+ }
83
+ console.log('coverage-gate: OK')
package/dist/confirm.js DELETED
@@ -1,105 +0,0 @@
1
- import * as readlinePromises from 'readline/promises';
2
- import { theme } from './theme.js';
3
- import { unifiedDiff, colorDiff } from './diff.js';
4
- import { translate, DEFAULT_LOCALE } from './i18n.js';
5
- export class ConfirmManager {
6
- settings;
7
- alwaysConfirm;
8
- allowedForSession;
9
- locale;
10
- constructor({ config, locale = DEFAULT_LOCALE, } = {}) {
11
- const c = config || {};
12
- this.locale = locale;
13
- this.settings = {
14
- write: c.write !== false,
15
- edit: c.edit !== false,
16
- bash: c.bash !== false,
17
- };
18
- // An invalid operator-supplied regex must NEVER crash the run. Fall back to
19
- // a literal substring match (case-insensitive) for that pattern.
20
- this.alwaysConfirm = (c.alwaysConfirm || []).map((p) => {
21
- try {
22
- return new RegExp(p, 'i');
23
- }
24
- catch {
25
- return new RegExp(escapeRegExp(p), 'i');
26
- }
27
- });
28
- this.allowedForSession = new Set();
29
- }
30
- _matchesAlwaysConfirm(command) {
31
- return this.alwaysConfirm.some((re) => re.test(command));
32
- }
33
- shouldAsk(kind, target = null) {
34
- if (kind === 'bash' && target && this._matchesAlwaysConfirm(target)) {
35
- return true;
36
- }
37
- if (!this.settings[kind])
38
- return false;
39
- if (this.allowedForSession.has(kind))
40
- return false;
41
- return true;
42
- }
43
- // Hot-update the language (from /config lang). The manager holds the locale
44
- // so its prompt follows the interface language without a restart.
45
- setLocale(locale) {
46
- this.locale = locale;
47
- }
48
- async ask({ kind, target, preview = null, message, }) {
49
- if (!this.shouldAsk(kind, target ?? null))
50
- return true;
51
- if (preview) {
52
- console.log(preview);
53
- }
54
- const t = translate(this.locale);
55
- const label = message || t('confirm.ask_label') + ' ' + kind + '?';
56
- const question = theme.warn(`${label} `) +
57
- theme.system('[') +
58
- theme.assistant('y') +
59
- theme.system(' = ' + t('common.yes') + ', ') +
60
- theme.error('n') +
61
- theme.system(' = ' + t('common.no') + ', ') +
62
- theme.user('a') +
63
- theme.system(' = ' + t('confirm.hint') + '] ');
64
- const answer = await this._prompt(question);
65
- if (answer === 'a') {
66
- if (kind !== 'bash' || !this._matchesAlwaysConfirm(target ?? '')) {
67
- this.allowedForSession.add(kind);
68
- }
69
- return true;
70
- }
71
- return answer === 'y';
72
- }
73
- async _prompt(question) {
74
- process.stdin.resume();
75
- if (process.stdin.isTTY && process.stdin.setRawMode) {
76
- process.stdin.setRawMode(false);
77
- }
78
- const rl = readlinePromises.createInterface({
79
- input: process.stdin,
80
- output: process.stdout,
81
- });
82
- try {
83
- const ans = await rl.question(question);
84
- const v = (ans || '').trim().toLowerCase();
85
- if (v === 'a' || v === 'always' || v === 'в')
86
- return 'a';
87
- if (v === 'y' || v === 'yes' || v === 'д' || v === 'да')
88
- return 'y';
89
- return 'n';
90
- }
91
- finally {
92
- rl.close();
93
- }
94
- }
95
- }
96
- // Escape a string so it can be used as a literal regex (used when an
97
- // operator-supplied alwaysConfirm pattern is invalid and we fall back to a
98
- // substring match).
99
- function escapeRegExp(s) {
100
- return s.replace(/[.*+?^${}()|[\]\\]/g, (m) => '\\' + m);
101
- }
102
- export function formatDiffPreview(oldText, newText, { label } = {}) {
103
- const diff = unifiedDiff(oldText, newText, { label });
104
- return colorDiff(diff);
105
- }