@nac3/forge-cli 1.23.1 → 1.23.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.
Files changed (52) hide show
  1. package/dist/bin/yf.js +0 -0
  2. package/dist/chat/server.d.ts.map +1 -1
  3. package/dist/chat/server.js +36 -8
  4. package/dist/chat/server.js.map +1 -1
  5. package/dist/commands/urazuke.d.ts.map +1 -1
  6. package/dist/commands/urazuke.js +22 -16
  7. package/dist/commands/urazuke.js.map +1 -1
  8. package/dist/core/error_catalog.d.ts +27 -0
  9. package/dist/core/error_catalog.d.ts.map +1 -1
  10. package/dist/core/error_catalog.js +55 -0
  11. package/dist/core/error_catalog.js.map +1 -1
  12. package/dist/core/error_formatter.d.ts +12 -0
  13. package/dist/core/error_formatter.d.ts.map +1 -1
  14. package/dist/core/error_formatter.js +19 -0
  15. package/dist/core/error_formatter.js.map +1 -1
  16. package/dist/relay/command_consumer.d.ts +10 -0
  17. package/dist/relay/command_consumer.d.ts.map +1 -1
  18. package/dist/relay/command_consumer.js +10 -1
  19. package/dist/relay/command_consumer.js.map +1 -1
  20. package/dist/relay/loopback_turn.d.ts +82 -0
  21. package/dist/relay/loopback_turn.d.ts.map +1 -0
  22. package/dist/relay/loopback_turn.js +171 -0
  23. package/dist/relay/loopback_turn.js.map +1 -0
  24. package/dist/urazuke/heuristics.d.ts +11 -0
  25. package/dist/urazuke/heuristics.d.ts.map +1 -1
  26. package/dist/urazuke/heuristics.js +15 -3
  27. package/dist/urazuke/heuristics.js.map +1 -1
  28. package/dist/urazuke/quality.d.ts +1 -4
  29. package/dist/urazuke/quality.d.ts.map +1 -1
  30. package/dist/urazuke/quality.js +3 -42
  31. package/dist/urazuke/quality.js.map +1 -1
  32. package/dist/urazuke/quality_doc.d.ts +11 -0
  33. package/dist/urazuke/quality_doc.d.ts.map +1 -0
  34. package/dist/urazuke/quality_doc.js +137 -0
  35. package/dist/urazuke/quality_doc.js.map +1 -0
  36. package/dist/urazuke/rule_report.d.ts +29 -0
  37. package/dist/urazuke/rule_report.d.ts.map +1 -0
  38. package/dist/urazuke/rule_report.js +239 -0
  39. package/dist/urazuke/rule_report.js.map +1 -0
  40. package/dist/version.d.ts +1 -1
  41. package/dist/version.js +1 -1
  42. package/package.json +18 -20
  43. package/src/i18n/catalogs/ar.json +7 -0
  44. package/src/i18n/catalogs/de.json +7 -0
  45. package/src/i18n/catalogs/en.json +7 -0
  46. package/src/i18n/catalogs/es.json +7 -0
  47. package/src/i18n/catalogs/fr.json +7 -0
  48. package/src/i18n/catalogs/hi.json +7 -0
  49. package/src/i18n/catalogs/it.json +7 -0
  50. package/src/i18n/catalogs/ja.json +7 -0
  51. package/src/i18n/catalogs/pt.json +7 -0
  52. package/src/i18n/catalogs/zh.json +7 -0
@@ -0,0 +1,137 @@
1
+ /**
2
+ * docs/CODE_QUALITY.md -- the artifact step 9 names, written from the
3
+ * definition in force.
4
+ *
5
+ * Split out of `quality.ts` (which measures) so the file that renders can
6
+ * carry the result per rule without either of the two crossing 300 lines --
7
+ * the limit CQ-03 declares and the one Forge measures on itself.
8
+ *
9
+ * TWO READINGS, NEVER MIXED. With a rule catalogue in force, every number
10
+ * in the threshold table comes from the definition and each row says who
11
+ * declared it (the method, the project, or nobody -- and an undeclared
12
+ * threshold is not measured). WITHOUT one, the two limits Forge still
13
+ * measures are declared as what they are: a value of this tool, not the
14
+ * method's limit. The one thing the annex forbids outright is a number of
15
+ * ours standing in the column the method governs.
16
+ *
17
+ * ASCII-only.
18
+ */
19
+ import fs from 'node:fs/promises';
20
+ import path from 'node:path';
21
+ import { renderRuleResults, renderUsability } from './rule_report.js';
22
+ const OWN_LIMITS_NOTE = 'La definicion en vigor de este proyecto no trae el catalogo de reglas del'
23
+ + ' Anexo H (no publica umbrales por regla), asi que los dos limites de abajo son un valor **propio'
24
+ + ' de Forge** y no el limite del metodo. En cuanto el proyecto adopte una definicion que los'
25
+ + ' publique, este documento mide contra los declarados y dice quien declara cada uno.';
26
+ function count(r, k) {
27
+ return r.native.violations.filter((x) => x.kind === k).length;
28
+ }
29
+ /** What the native meters measured, keyed by the threshold id of the
30
+ * definition in force. Labelled as this installation's instrument: the
31
+ * method publishes the threshold, not the checker (PND-219). */
32
+ function nativeMeasured(r) {
33
+ const files = count(r, 'file_lines');
34
+ const fns = count(r, 'function_lines');
35
+ return {
36
+ lines_per_file: r.native.max_file_lines + ' el maximo medido; '
37
+ + (files ? files + ' archivos pasan el limite' : 'ninguno pasa el limite')
38
+ + ' (medidor nativo de esta instalacion)',
39
+ lines_per_function: r.native.max_function_lines + ' el maximo medido; '
40
+ + (fns ? fns + ' funciones pasan el limite' : 'ninguna pasa el limite')
41
+ + ' (medidor nativo de esta instalacion)',
42
+ ...(r.coverage_pct != null
43
+ ? { minimum_coverage: r.coverage_pct + ' por ciento, con piso del trinquete '
44
+ + (r.ratchet.next.coverage_pct ?? '-') }
45
+ : {}),
46
+ ...(r.mutation_score != null
47
+ ? { mutation_target: r.mutation_score + ' por ciento de mutantes muertos' }
48
+ : {}),
49
+ };
50
+ }
51
+ function toolsSection(r) {
52
+ return [
53
+ '## Herramientas',
54
+ '',
55
+ '- Bateria: `' + (r.stack.test_command || '(sin comando de tests)') + '`',
56
+ '- Lint / formato: ' + (r.stack.lint_commands.length
57
+ ? r.stack.lint_commands.map((c) => '`' + c + '`').join(', ')
58
+ : '(ninguno instalado; medidores nativos de Forge)'),
59
+ '- Cobertura: ' + (r.stack.coverage_command
60
+ ? '`' + r.stack.coverage_command + '` -> ' + r.stack.coverage_file : '(no disponible)'),
61
+ '- Mutacion: ' + (r.stack.mutation_command
62
+ ? r.stack.mutation_tool + ' (`' + r.stack.mutation_command + '`)' : '(no disponible)'),
63
+ '- Lint / formato hoy: ' + r.lint.filter((l) => l.exit_code !== 0).length + ' fallos sobre '
64
+ + r.lint.length + ' comandos (' + (r.lint.every((l) => l.exit_code === 0) ? 'ok' : 'ROJO') + ')',
65
+ '',
66
+ ];
67
+ }
68
+ /** The fallback table, for a project with no rule catalogue in force. */
69
+ function ownLimits(r) {
70
+ return [
71
+ '## Limites y valores medidos',
72
+ '',
73
+ OWN_LIMITS_NOTE,
74
+ '',
75
+ '| Medida | Limite (propio de Forge) | Medido | Estado |',
76
+ '|---|---|---|---|',
77
+ '| Lineas por archivo (max) | ' + r.limits.max_file_lines + ' | ' + r.native.max_file_lines
78
+ + ' | ' + (count(r, 'file_lines') ? count(r, 'file_lines') + ' archivos pasan el limite' : 'ok') + ' |',
79
+ '| Lineas por funcion (max) | ' + r.limits.max_function_lines + ' | ' + r.native.max_function_lines
80
+ + ' | ' + (count(r, 'function_lines') ? count(r, 'function_lines') + ' funciones pasan el limite' : 'ok') + ' |',
81
+ '| Cobertura de lineas (%) | piso ' + (r.ratchet.next.coverage_pct ?? '-') + ' | '
82
+ + (r.coverage_pct ?? '-') + ' | ' + (r.coverage_pct != null ? 'trinquete' : 'sin medir') + ' |',
83
+ '| Puntaje de mutacion (%) | piso ' + (r.ratchet.next.mutation_score ?? '-') + ' | '
84
+ + (r.mutation_score ?? '-') + ' | ' + (r.mutation_score != null ? 'trinquete' : 'sin medir') + ' |',
85
+ '',
86
+ ];
87
+ }
88
+ function failures(v) {
89
+ return [
90
+ '## Lo que hoy falla (' + v.length + ')',
91
+ '',
92
+ ...(v.length ? v.slice(0, 80).map((x) => '- ' + x.kind + ': ' + x.where + ' (' + x.value + ' > ' + x.limit + ')') : ['- nada']),
93
+ ...(v.length > 80 ? ['- ... y ' + (v.length - 80) + ' mas (yf urazuke quality check --json)'] : []),
94
+ '',
95
+ ];
96
+ }
97
+ /** docs/CODE_QUALITY.md. Rewritten on every check; the history of the
98
+ * numbers lives in the ratchet, and the owner's prose is preserved. */
99
+ export function renderQualityDoc(r, prevBody, rs) {
100
+ const keep = prevBody ? (/## Decisiones del dueno[\s\S]*$/.exec(prevBody)?.[0] ?? '') : '';
101
+ const lines = [
102
+ '# Calidad del codigo verificada por maquina',
103
+ '',
104
+ 'Generado por `yf urazuke quality check` el ' + new Date().toISOString() + '. Stack: ' + r.stack.label + '.',
105
+ 'Los numeros de abajo son medidos; el trinquete (`.forge/quality-ratchet.json`) solo deja mejorar.',
106
+ '',
107
+ ...toolsSection(r),
108
+ ...(rs ? renderRuleResults(rs, nativeMeasured(r)) : ownLimits(r)),
109
+ ...failures(r.native.violations),
110
+ '## Trinquete',
111
+ '',
112
+ r.ratchet.ok ? '- en verde: los numeros no empeoraron.' : '- EN ROJO: ' + r.ratchet.reasons.join('; '),
113
+ '',
114
+ keep || '## Decisiones del dueno\n\n_Que se arregla ahora (un pendiente cada uno) y que se tolera con fecha._\n',
115
+ ];
116
+ return lines.join('\n');
117
+ }
118
+ /** Write the two artifacts step 9 names, preserving the owner's prose in
119
+ * each. The second one only exists when the definition in force publishes
120
+ * usability rules: an empty USABILITY.md would pass a must_contain by
121
+ * accident and say nothing. Returns the relative paths written. */
122
+ export async function writeStep9Docs(root, r, rs) {
123
+ const written = [];
124
+ const one = async (rel, render) => {
125
+ const target = path.join(root, rel);
126
+ const prev = await fs.readFile(target, 'utf8').catch(() => '');
127
+ await fs.mkdir(path.dirname(target), { recursive: true });
128
+ await fs.writeFile(target, render(prev), 'utf8');
129
+ written.push(rel);
130
+ };
131
+ await one('docs/CODE_QUALITY.md', (prev) => renderQualityDoc(r, prev, rs));
132
+ if (rs && rs.rules.some((x) => x.group === 'usability')) {
133
+ await one('docs/USABILITY.md', (prev) => renderUsability(rs, prev));
134
+ }
135
+ return written;
136
+ }
137
+ //# sourceMappingURL=quality_doc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality_doc.js","sourceRoot":"","sources":["../../src/urazuke/quality_doc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { Ruleset, ThresholdView } from './heuristics.js';
2
+ /** The rule catalogue of the definition in force, or undefined when the
3
+ * definition does not publish one -- the compiled base catalogue is schema 1
4
+ * and carries no rules, so a project that never adopted a published file has
5
+ * nothing to report per rule, and the document says so instead of inventing
6
+ * a catalogue. */
7
+ export declare function rulesetInForce(projectRoot: string): Promise<Ruleset | undefined>;
8
+ /** The two limits Forge's native meter can measure, when the definition in
9
+ * force declares them (annex value, or the project's own override). */
10
+ export interface RuleLimits {
11
+ max_file_lines?: number;
12
+ max_function_lines?: number;
13
+ }
14
+ /** The measurable limits, taken from the definition in force instead of
15
+ * from a constant of Forge. An undeclared threshold yields nothing: the
16
+ * caller keeps its own default and the document says it is its own. */
17
+ export declare function limitsFromRuleset(rs?: Ruleset): RuleLimits;
18
+ /** Who declared a threshold, in the reader's words. */
19
+ export declare function declaredBy(t: ThresholdView): string;
20
+ /** The threshold table: id, rule, value, WHO declared it, and -- for the
21
+ * two Forge measures natively -- what was measured against it. */
22
+ export declare function thresholdRows(rs: Ruleset, measured: Record<string, string>): string[];
23
+ /** The section the quality document carries so step 9 gets the result per
24
+ * rule and not a single number. */
25
+ export declare function renderRuleResults(rs: Ruleset, measured: Record<string, string>): string[];
26
+ /** docs/USABILITY.md -- the artifact step 9 adds in schema 2: the result
27
+ * per usability rule, with its declared exceptions. */
28
+ export declare function renderUsability(rs: Ruleset, prevBody?: string): string;
29
+ //# sourceMappingURL=rule_report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule_report.d.ts","sourceRoot":"","sources":["../../src/urazuke/rule_report.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,OAAO,EAAgB,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE5E;;;;mBAImB;AACnB,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAMtF;AAED;wEACwE;AACxE,MAAM,WAAW,UAAU;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAOD;;wEAEwE;AACxE,wBAAgB,iBAAiB,CAAC,EAAE,CAAC,EAAE,OAAO,GAAG,UAAU,CAQ1D;AAED,uDAAuD;AACvD,wBAAgB,UAAU,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,CASnD;AAsDD;mEACmE;AACnE,wBAAgB,aAAa,CAAC,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,CASrF;AAgBD;oCACoC;AACpC,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,CAqBzF;AAED;wDACwD;AACxD,wBAAgB,eAAe,CAAC,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAgDtE"}
@@ -0,0 +1,239 @@
1
+ /**
2
+ * THE RESULT PER RULE, WITH ITS ID -- and the provenance of every
3
+ * threshold (Annex H, step 9's two documents).
4
+ *
5
+ * Why this file exists. Step 9 of the published catalogue names two
6
+ * artifacts with a `must_contain` each: `docs/CODE_QUALITY.md` has to carry
7
+ * `CQ-\d\d` ("the result per rule, not as a single number") and
8
+ * `docs/USABILITY.md` has to carry `UX-\d\d` ("the result per usability
9
+ * rule, with its declared exceptions"). Until 2026-10-28 Forge wrote the
10
+ * first document with four aggregate numbers and no rule id at all, and
11
+ * never wrote the second: so the document Forge itself generates failed
12
+ * Forge's own `artifacts` evaluator, and step 9 came out red in every
13
+ * project this tool writes -- not for want of the schema-2 evaluators
14
+ * (PND-215), but through the one evaluator that was already implemented.
15
+ *
16
+ * AND THE COLUMN THE METHOD GOVERNS. The same table printed `300` and `40`
17
+ * under the heading "Limite" with no provenance. Two of the five published
18
+ * thresholds are declared by the annex, one by the owner and two by neither
19
+ * (`paths_per_function`, `minimum_coverage`, `mutation_target` -- the last
20
+ * two by the ratchet and by the owner once there are real users). The annex
21
+ * is explicit about the ones nobody declared: "it is reported as an
22
+ * undeclared threshold. Without approximating, without inheriting in
23
+ * silence and without inventing". So each row says WHO declared the number,
24
+ * and an undeclared threshold shows no number and is not measured.
25
+ *
26
+ * WHAT THIS FILE WILL NOT DO. It will not turn a rule the installation
27
+ * cannot measure into a green one. `resolveRuleset` resolves every active
28
+ * rule's checker to `not_published` (the data publishes the instrument and
29
+ * the severity per rule, but not the cell that says what measures it -- see
30
+ * PND-219), so the result column says SIN MEDIR and names why. The native
31
+ * meters Forge does run live in their own section, tied to the rule id
32
+ * whose threshold they measure and labelled as this installation's
33
+ * instrument, never as the method's. A number of ours in the method's
34
+ * column is the one thing the annex forbids outright.
35
+ *
36
+ * ASCII-only.
37
+ */
38
+ import { verdictFor } from './manual_cases.js';
39
+ /** The rule catalogue of the definition in force, or undefined when the
40
+ * definition does not publish one -- the compiled base catalogue is schema 1
41
+ * and carries no rules, so a project that never adopted a published file has
42
+ * nothing to report per rule, and the document says so instead of inventing
43
+ * a catalogue. */
44
+ export async function rulesetInForce(projectRoot) {
45
+ const { gatesInForce } = await import('./gate.js');
46
+ const { resolveRuleset } = await import('./heuristics.js');
47
+ const gates = await gatesInForce(projectRoot);
48
+ const rs = await resolveRuleset({ projectRoot, gates });
49
+ return rs.rules.length ? rs : undefined;
50
+ }
51
+ const LIMIT_OF = {
52
+ lines_per_file: 'max_file_lines',
53
+ lines_per_function: 'max_function_lines',
54
+ };
55
+ /** The measurable limits, taken from the definition in force instead of
56
+ * from a constant of Forge. An undeclared threshold yields nothing: the
57
+ * caller keeps its own default and the document says it is its own. */
58
+ export function limitsFromRuleset(rs) {
59
+ const out = {};
60
+ for (const t of rs?.thresholds ?? []) {
61
+ const key = LIMIT_OF[t.id];
62
+ if (!key || !t.declared || typeof t.value !== 'number')
63
+ continue;
64
+ out[key] = t.value;
65
+ }
66
+ return out;
67
+ }
68
+ /** Who declared a threshold, in the reader's words. */
69
+ export function declaredBy(t) {
70
+ if (t.declared && t.source === 'project')
71
+ return 'el proyecto, en .forge/project-settings.json';
72
+ if (t.declared)
73
+ return 'el metodo, en el anexo';
74
+ /* The method's own words, quoted: paraphrasing who declares a threshold
75
+ * is how a consumer ends up inventing layer 2. The quote marks make the
76
+ * language change legible instead of looking like a bug. */
77
+ return t.declared_by
78
+ ? 'nadie todavia -- el metodo dice que lo declara: "' + t.declared_by + '"'
79
+ : 'nadie -- la definicion en vigor no dice ni quien lo declararia';
80
+ }
81
+ const SEV = { blocks: 'bloquea', warns: 'avisa', records: 'queda escrito' };
82
+ /** The state of a rule, said in full: a switched-off rule carries who
83
+ * authorized it and until when, because that is the whole point of the
84
+ * record the method demands. */
85
+ function stateOf(r) {
86
+ if (r.state === 'group_off')
87
+ return 'GRUPO APAGADO -- nunca se lee como cumplido';
88
+ if (r.state === 'switched_off') {
89
+ const rec = r.record;
90
+ return 'APAGADA por ' + (rec?.authorized_by ?? '?') + ', revision ' + (rec?.review_date ?? '?')
91
+ + ': ' + (rec?.reason ?? '?');
92
+ }
93
+ if (r.state === 'out_of_scope')
94
+ return 'FUERA DE ALCANCE -- ' + (r.why ?? 'no aplica a este proyecto');
95
+ return 'activa';
96
+ }
97
+ /** The result of a rule: measured green, measured red, judged by a person,
98
+ * or not measured at all -- never folded into a colour it did not earn. */
99
+ function resultOf(rs, r) {
100
+ if (r.state !== 'active')
101
+ return 'no se mide en este estado';
102
+ if (r.human_red || r.instrument.includes('manual_case')) {
103
+ const v = verdictFor(rs.manual_cases, r.id);
104
+ if (!v)
105
+ return 'LA JUZGA UNA PERSONA -- sin veredicto en el registro';
106
+ return 'LA JUZGO UNA PERSONA: ' + (v.verdict === 'passed' ? 'paso' : 'FALLO')
107
+ + ' -- ' + v.judged_by + ', ' + v.at;
108
+ }
109
+ if (r.measured)
110
+ return r.passing ? 'medida en verde' : 'medida en ROJO';
111
+ return 'SIN MEDIR -- la definicion en vigor no publica con que se mide esta regla';
112
+ }
113
+ function ruleRows(rs, group) {
114
+ const rows = ['| Regla | Familia | Severidad | Estado | Resultado | Instrumento declarado |',
115
+ '|---|---|---|---|---|---|'];
116
+ for (const r of rs.rules.filter((x) => x.group === group)) {
117
+ rows.push('| ' + r.id + ' | ' + (r.family || '-') + ' | ' + (SEV[r.severity] ?? r.severity)
118
+ + ' | ' + stateOf(r) + ' | ' + resultOf(rs, r)
119
+ + ' | ' + (r.instrument.length ? r.instrument.join(', ') : 'sin instrumento publicado') + ' |');
120
+ }
121
+ if (rows.length === 2)
122
+ rows.push('| (ninguna) | - | - | - | la definicion en vigor no trae reglas de este grupo | - |');
123
+ return rows;
124
+ }
125
+ /** One line per rule with the sentence the annex extracted, so a reader
126
+ * does not need the annex open to know what the id means. */
127
+ function statementList(rs, group) {
128
+ const out = [];
129
+ for (const r of rs.rules.filter((x) => x.group === group)) {
130
+ out.push('- **' + r.id + '**: ' + (r.statement ?? '(la definicion en vigor no trae el enunciado)'));
131
+ }
132
+ return out.length ? out : ['- (ninguna)'];
133
+ }
134
+ /** The threshold table: id, rule, value, WHO declared it, and -- for the
135
+ * two Forge measures natively -- what was measured against it. */
136
+ export function thresholdRows(rs, measured) {
137
+ const rows = ['| Umbral | Regla | Limite | Quien lo declara | Medido |', '|---|---|---|---|---|'];
138
+ for (const t of rs.thresholds) {
139
+ const limit = t.declared ? String(t.value) : 'SIN DECLARAR';
140
+ const m = measuredCell(t, measured[t.id]);
141
+ rows.push('| ' + t.id + ' | ' + (t.rule || '-') + ' | ' + limit + ' | ' + declaredBy(t) + ' | ' + m + ' |');
142
+ }
143
+ if (rows.length === 2)
144
+ rows.push('| (ninguno) | - | - | la definicion en vigor no publica umbrales | - |');
145
+ return rows;
146
+ }
147
+ /** The measured cell. A declared threshold is compared; an undeclared one
148
+ * is NOT measured against anything invented -- when a meter still produced a
149
+ * number (the coverage the ratchet floors), it is shown as a number with no
150
+ * limit to compare it to, which is a different claim from a verdict. */
151
+ function measuredCell(t, m) {
152
+ if (t.declared)
153
+ return m ?? 'esta instalacion no lo mide';
154
+ if (m)
155
+ return 'no se mide contra un limite (ninguno declarado); medido igual: ' + m;
156
+ return 'no se mide -- el metodo dice: "' + undeclaredNote(t) + '"';
157
+ }
158
+ function undeclaredNote(t) {
159
+ return t.note ?? 'el metodo exige que el limite se declare y no fija el numero';
160
+ }
161
+ /** The section the quality document carries so step 9 gets the result per
162
+ * rule and not a single number. */
163
+ export function renderRuleResults(rs, measured) {
164
+ return [
165
+ '## Resultado por regla (' + rs.rules.filter((r) => r.group === 'code_quality').length + ' reglas de codigo)',
166
+ '',
167
+ 'Catalogo ' + rs.catalog_version + '. Las reglas, sus familias, sus severidades y sus umbrales'
168
+ + ' salen de la definicion en vigor: ningun numero de abajo es una constante de esta herramienta.',
169
+ '',
170
+ ...ruleRows(rs, 'code_quality'),
171
+ '',
172
+ '## Umbrales, y quien declara cada uno',
173
+ '',
174
+ ...thresholdRows(rs, measured),
175
+ '',
176
+ ...(rs.could_not_verify.length
177
+ ? ['## Lo que esta instalacion NO pudo verificar', '', ...rs.could_not_verify.map((c) => '- ' + c), '']
178
+ : []),
179
+ '## Que dice cada regla',
180
+ '',
181
+ ...statementList(rs, 'code_quality'),
182
+ '',
183
+ ];
184
+ }
185
+ /** docs/USABILITY.md -- the artifact step 9 adds in schema 2: the result
186
+ * per usability rule, with its declared exceptions. */
187
+ export function renderUsability(rs, prevBody) {
188
+ const keep = prevBody ? (/## Decisiones del dueno[\s\S]*$/.exec(prevBody)?.[0] ?? '') : '';
189
+ const ux = rs.rules.filter((r) => r.group === 'usability');
190
+ const off = ux.filter((r) => r.state === 'switched_off');
191
+ const L = [
192
+ '# Usabilidad verificada, regla por regla',
193
+ '',
194
+ 'Generado por `yf urazuke quality check` el ' + new Date().toISOString() + '.',
195
+ 'Catalogo ' + rs.catalog_version + ' | adaptador ' + (rs.adapter ?? '(sin declarar)')
196
+ + ' | usuarios reales: ' + (rs.real_users ? 'si' : 'no declarados'),
197
+ '',
198
+ 'Veintisiete de las cuarenta y cinco reglas del anexo son de usabilidad, y la mayoria las juzga'
199
+ + ' una persona: el instrumento que el metodo les pone es un caso manual, no un medidor. Un caso'
200
+ + ' manual sin nombre y sin fecha no es un veredicto, y aca se ve como lo que es: ausente.',
201
+ '',
202
+ '## Resultado por regla (' + ux.length + ')',
203
+ '',
204
+ ...ruleRows(rs, 'usability'),
205
+ '',
206
+ '## Las excepciones declaradas',
207
+ '',
208
+ ];
209
+ if (!off.length && !rs.group_off.includes('usability'))
210
+ L.push('- ninguna regla de usabilidad esta apagada.');
211
+ for (const r of off) {
212
+ const rec = r.record;
213
+ L.push('- ' + r.id + ': apagada por ' + (rec?.authorized_by ?? '?') + ', revision '
214
+ + (rec?.review_date ?? '?') + '. ' + (rec?.reason ?? '?'));
215
+ }
216
+ if (rs.group_off.includes('usability')) {
217
+ L.push('- el grupo usability esta apagado entero: NUNCA se lee como cumplido.');
218
+ }
219
+ L.push('', '## Los veredictos de las personas', '');
220
+ const human = ux.filter((r) => r.human_red || r.instrument.includes('manual_case'));
221
+ if (!human.length)
222
+ L.push('- ninguna regla de usabilidad pide el juicio de una persona en esta definicion.');
223
+ for (const r of human) {
224
+ const v = verdictFor(rs.manual_cases, r.id);
225
+ L.push('- ' + r.id + ': ' + (v
226
+ ? (v.verdict === 'passed' ? 'paso' : 'FALLO') + ' -- ' + v.judged_by + ', ' + v.at
227
+ + (v.profile ? ' (perfil ' + v.profile + ')' : '') + (v.note ? '. ' + v.note : '')
228
+ : 'sin veredicto. Nadie la juzgo todavia.'));
229
+ }
230
+ if (rs.validity.invalidating.length) {
231
+ L.push('', '## La declaracion es INVALIDA', '');
232
+ for (const p of rs.validity.invalidating)
233
+ L.push('- ' + p);
234
+ }
235
+ L.push('', '## Que dice cada regla', '', ...statementList(rs, 'usability'), '');
236
+ L.push(keep || '## Decisiones del dueno\n\n_Que se arregla ahora (un pendiente cada uno) y que se tolera con fecha._\n');
237
+ return L.join('\n');
238
+ }
239
+ //# sourceMappingURL=rule_report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule_report.js","sourceRoot":"","sources":["../../src/urazuke/rule_report.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -2,5 +2,5 @@
2
2
  * Yujin Forge CLI version. Kept in sync with package.json by the npm
3
3
  * "version" lifecycle (scripts/sync_version.mjs) so the two never drift.
4
4
  */
5
- export declare const VERSION = "1.23.1";
5
+ export declare const VERSION = "1.23.3";
6
6
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -2,5 +2,5 @@
2
2
  * Yujin Forge CLI version. Kept in sync with package.json by the npm
3
3
  * "version" lifecycle (scripts/sync_version.mjs) so the two never drift.
4
4
  */
5
- export const VERSION = '1.23.1';
5
+ export const VERSION = '1.23.3';
6
6
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nac3/forge-cli",
3
- "version": "1.23.1",
3
+ "version": "1.23.3",
4
4
  "description": "Yujin Forge -- voice-first NAC-3 React development framework. CLI + chat panel + spec ingest + 10-format document reader + voice loop.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Pablo Kuschnirof <pablo@rpaforce.com>",
@@ -15,23 +15,6 @@
15
15
  "exports": {
16
16
  ".": "./dist/index.js"
17
17
  },
18
- "scripts": {
19
- "version": "node scripts/sync_version.mjs && git add src/version.ts",
20
- "build": "node scripts/clean_dist.mjs && tsc && node scripts/copy_qa_assets.mjs",
21
- "dev": "tsx watch src/bin/yf.ts",
22
- "typecheck": "tsc --noEmit",
23
- "typecheck:all": "pnpm typecheck && pnpm --filter @yujin/hito4-server typecheck && pnpm --filter @yujin/forge-mobile typecheck",
24
- "test": "vitest run",
25
- "test:watch": "vitest",
26
- "lint": "tsc --noEmit",
27
- "yf": "tsx src/bin/yf.ts",
28
- "catalog:lint": "node scripts/catalog_lint.mjs",
29
- "pairing:check": "node scripts/check_pairing_sync.mjs",
30
- "brain-matrix:gate": "node scripts/brain_matrix_gate.mjs",
31
- "hito4:lint": "node scripts/hito4_lint_bundle.mjs",
32
- "publish-alpha-emergency": "node scripts/publish_alpha_emergency.mjs",
33
- "prepublishOnly": "pnpm run build && pnpm run typecheck && pnpm run catalog:lint && pnpm run test && pnpm run brain-matrix:gate && pnpm run hito4:lint"
34
- },
35
18
  "dependencies": {
36
19
  "@anthropic-ai/sdk": "^0.32.1",
37
20
  "@aws-sdk/client-ecs": "^3.1053.0",
@@ -68,7 +51,6 @@
68
51
  "node": ">=18.17",
69
52
  "pnpm": ">=9"
70
53
  },
71
- "packageManager": "pnpm@11.3.0",
72
54
  "files": [
73
55
  "dist",
74
56
  "templates",
@@ -113,5 +95,21 @@
113
95
  "publishConfig": {
114
96
  "access": "public",
115
97
  "tag": "latest"
98
+ },
99
+ "scripts": {
100
+ "version": "node scripts/sync_version.mjs && git add src/version.ts",
101
+ "build": "node scripts/clean_dist.mjs && tsc && node scripts/copy_qa_assets.mjs",
102
+ "dev": "tsx watch src/bin/yf.ts",
103
+ "typecheck": "tsc --noEmit",
104
+ "typecheck:all": "pnpm typecheck && pnpm --filter @yujin/hito4-server typecheck && pnpm --filter @yujin/forge-mobile typecheck",
105
+ "test": "vitest run",
106
+ "test:watch": "vitest",
107
+ "lint": "tsc --noEmit",
108
+ "yf": "tsx src/bin/yf.ts",
109
+ "catalog:lint": "node scripts/catalog_lint.mjs",
110
+ "pairing:check": "node scripts/check_pairing_sync.mjs",
111
+ "brain-matrix:gate": "node scripts/brain_matrix_gate.mjs",
112
+ "hito4:lint": "node scripts/hito4_lint_bundle.mjs",
113
+ "publish-alpha-emergency": "node scripts/publish_alpha_emergency.mjs"
116
114
  }
117
- }
115
+ }
@@ -128,6 +128,13 @@
128
128
  "error.project_not_registered.why": "يتطلب verb المستدعى project root نشط لكن ~/.yujin-forge/projects.json ليس به إدخالات.",
129
129
  "error.project_not_registered.fix": "أنشئ واحدا بـ yujin.project.init أو سجل واحدا موجودا بـ yf projects add.",
130
130
  "error.project_not_registered.cmd": "yf projects scan",
131
+ "error.mobile_turn_unanswered.what": "لم يُرجع سطح المكتب ردًا على طلبك خلال {minutes} دقيقة.",
132
+ "error.mobile_turn_unanswered.why": "قد تكون الجولة ما زالت تعمل: ما انتهى هو الانتظار، لا العمل. سطح المكتب لا يتوقف.",
133
+ "error.mobile_turn_unanswered.fix": "راجع محادثة سطح المكتب: إذا انتهت الجولة فالرد موجود هناك. لا تعد إرسال الطلب قبل أن تتحقق، وإلا سيُنفَّذ مرتين.",
134
+ "error.mobile_turn_undelivered.what": "لم أتمكن من تسليم طلبك إلى سطح المكتب.",
135
+ "error.mobile_turn_undelivered.why": "خادم المحادثة في سطح المكتب لم يكن يستمع على المنفذ {port}. لم يُنفَّذ أي شيء هنا.",
136
+ "error.mobile_turn_undelivered.fix": "افتح لوحة Forge على سطح المكتب (أو شغّلها بـ yf chat) ثم أعد إرسال الطلب.",
137
+ "error.mobile_turn_undelivered.cmd": "yf chat",
131
138
  "panel.button.agents": "الوكلاء",
132
139
  "panel.agents.title": "الوكلاء",
133
140
  "panel.agents.subtitle": "المدير والوكلاء الفرعيون المسجلون في هذا المشروع",
@@ -128,6 +128,13 @@
128
128
  "error.project_not_registered.why": "Das aufgerufene Verb benoetigt einen aktiven Project-Root, aber ~/.yujin-forge/projects.json hat keine Eintraege.",
129
129
  "error.project_not_registered.fix": "Erstellen Sie eines mit yujin.project.init oder registrieren Sie ein existierendes mit yf projects add.",
130
130
  "error.project_not_registered.cmd": "yf projects scan",
131
+ "error.mobile_turn_unanswered.what": "Der Desktop hat deine Anfrage in {minutes} Minuten nicht beantwortet.",
132
+ "error.mobile_turn_unanswered.why": "Der Turn laeuft moeglicherweise weiter: abgelaufen ist das Warten, nicht die Arbeit. Der Desktop hoert nicht auf.",
133
+ "error.mobile_turn_unanswered.fix": "Schau in den Desktop-Chat: wenn der Turn fertig ist, steht die Antwort dort. Sende die Anfrage nicht erneut, ohne nachzusehen, sonst laeuft sie zweimal.",
134
+ "error.mobile_turn_undelivered.what": "Ich konnte deine Anfrage nicht an den Desktop uebergeben.",
135
+ "error.mobile_turn_undelivered.why": "Der Chat-Server des Desktops lauschte nicht auf Port {port}. Hier wurde nichts ausgefuehrt.",
136
+ "error.mobile_turn_undelivered.fix": "Oeffne das Forge-Panel auf dem Desktop (oder starte es mit yf chat) und sende die Anfrage erneut.",
137
+ "error.mobile_turn_undelivered.cmd": "yf chat",
131
138
  "panel.button.agents": "Agenten",
132
139
  "panel.agents.title": "Agenten",
133
140
  "panel.agents.subtitle": "Director und Sub-Agenten registriert in diesem Projekt",
@@ -128,6 +128,13 @@
128
128
  "error.project_not_registered.why": "The verb you invoked needs an active project root but ~/.yujin-forge/projects.json has no entries.",
129
129
  "error.project_not_registered.fix": "Create one with yujin.project.init or register an existing one with yf projects add.",
130
130
  "error.project_not_registered.cmd": "yf projects scan",
131
+ "error.mobile_turn_unanswered.what": "The desktop did not return an answer to your request within {minutes} minutes.",
132
+ "error.mobile_turn_unanswered.why": "The turn may still be running: what expired is the wait, not the work. The desktop does not stop.",
133
+ "error.mobile_turn_unanswered.fix": "Check the desktop chat: if the turn finished, the answer is there. Do not resend the request before looking, or it runs twice.",
134
+ "error.mobile_turn_undelivered.what": "I could not hand your request to the desktop.",
135
+ "error.mobile_turn_undelivered.why": "The desktop chat server was not listening on port {port}. Nothing ran here.",
136
+ "error.mobile_turn_undelivered.fix": "Open the Forge panel on the desktop (or start it with yf chat) and send the request again.",
137
+ "error.mobile_turn_undelivered.cmd": "yf chat",
131
138
  "panel.button.agents": "Agents",
132
139
  "panel.agents.title": "Agents",
133
140
  "panel.agents.subtitle": "Director and sub-agents registered in this project",
@@ -128,6 +128,13 @@
128
128
  "error.project_not_registered.why": "El verb que invocaste requiere project root activo pero ~/.yujin-forge/projects.json no tiene entradas.",
129
129
  "error.project_not_registered.fix": "Crea uno con yujin.project.init o registra uno existente con yf projects add.",
130
130
  "error.project_not_registered.cmd": "yf projects scan",
131
+ "error.mobile_turn_unanswered.what": "El escritorio no devolvio la respuesta de tu pedido en {minutes} minutos.",
132
+ "error.mobile_turn_unanswered.why": "El turno puede seguir corriendo: lo que vencio es la espera, no el trabajo. El escritorio no para.",
133
+ "error.mobile_turn_unanswered.fix": "Mira el chat del escritorio: si el turno termino, la respuesta esta ahi. No repitas el pedido sin fijarte, o se ejecuta dos veces.",
134
+ "error.mobile_turn_undelivered.what": "No pude entregarle tu pedido al escritorio.",
135
+ "error.mobile_turn_undelivered.why": "El servidor de chat del escritorio no estaba escuchando en el puerto {port}. Aca no se ejecuto nada.",
136
+ "error.mobile_turn_undelivered.fix": "Abri el panel de Forge en el escritorio (o arrancalo con yf chat) y volve a mandar el pedido.",
137
+ "error.mobile_turn_undelivered.cmd": "yf chat",
131
138
  "panel.button.agents": "Agentes",
132
139
  "panel.agents.title": "Agentes",
133
140
  "panel.agents.subtitle": "Director + sub-agentes registrados en este proyecto",
@@ -128,6 +128,13 @@
128
128
  "error.project_not_registered.why": "Le verb invoque necessite un project root actif mais ~/.yujin-forge/projects.json n'a pas d'entrees.",
129
129
  "error.project_not_registered.fix": "Creez-en un avec yujin.project.init ou enregistrez un existant avec yf projects add.",
130
130
  "error.project_not_registered.cmd": "yf projects scan",
131
+ "error.mobile_turn_unanswered.what": "Le bureau n'a pas renvoye de reponse a ta demande en {minutes} minutes.",
132
+ "error.mobile_turn_unanswered.why": "Le tour peut encore tourner : ce qui a expire, c'est l'attente, pas le travail. Le bureau ne s'arrete pas.",
133
+ "error.mobile_turn_unanswered.fix": "Regarde le chat du bureau : si le tour est fini, la reponse y est. Ne renvoie pas la demande sans verifier, sinon elle s'execute deux fois.",
134
+ "error.mobile_turn_undelivered.what": "Je n'ai pas pu transmettre ta demande au bureau.",
135
+ "error.mobile_turn_undelivered.why": "Le serveur de chat du bureau n'ecoutait pas sur le port {port}. Rien n'a ete execute ici.",
136
+ "error.mobile_turn_undelivered.fix": "Ouvre le panneau Forge sur le bureau (ou lance-le avec yf chat) puis renvoie la demande.",
137
+ "error.mobile_turn_undelivered.cmd": "yf chat",
131
138
  "panel.button.agents": "Agents",
132
139
  "panel.agents.title": "Agents",
133
140
  "panel.agents.subtitle": "Director et sous-agents enregistres dans ce projet",
@@ -128,6 +128,13 @@
128
128
  "error.project_not_registered.why": "invoked verb को सक्रिय project root की आवश्यकता है लेकिन ~/.yujin-forge/projects.json में कोई entries नहीं हैं।",
129
129
  "error.project_not_registered.fix": "yujin.project.init के साथ एक बनाएं या yf projects add के साथ एक मौजूदा पंजीकृत करें।",
130
130
  "error.project_not_registered.cmd": "yf projects scan",
131
+ "error.mobile_turn_unanswered.what": "डेस्कटॉप ने {minutes} मिनट में आपके अनुरोध का उत्तर नहीं लौटाया।",
132
+ "error.mobile_turn_unanswered.why": "टर्न अभी भी चल सकता है: जो समाप्त हुआ वह प्रतीक्षा है, काम नहीं। डेस्कटॉप रुकता नहीं है।",
133
+ "error.mobile_turn_unanswered.fix": "डेस्कटॉप का चैट देखें: अगर टर्न पूरा हो गया है, तो उत्तर वहीं है। देखे बिना अनुरोध दोबारा न भेजें, वरना वह दो बार चलेगा।",
134
+ "error.mobile_turn_undelivered.what": "मैं आपका अनुरोध डेस्कटॉप तक नहीं पहुंचा सका।",
135
+ "error.mobile_turn_undelivered.why": "डेस्कटॉप का चैट सर्वर पोर्ट {port} पर सुन नहीं रहा था। यहां कुछ भी नहीं चला।",
136
+ "error.mobile_turn_undelivered.fix": "डेस्कटॉप पर Forge पैनल खोलें (या yf chat से शुरू करें) और अनुरोध दोबारा भेजें।",
137
+ "error.mobile_turn_undelivered.cmd": "yf chat",
131
138
  "panel.button.agents": "एजेंट",
132
139
  "panel.agents.title": "एजेंट",
133
140
  "panel.agents.subtitle": "इस परियोजना में पंजीकृत निदेशक और उप-एजेंट",
@@ -128,6 +128,13 @@
128
128
  "error.project_not_registered.why": "Il verb invocato richiede un project root attivo ma ~/.yujin-forge/projects.json non ha voci.",
129
129
  "error.project_not_registered.fix": "Creane uno con yujin.project.init o registrane uno esistente con yf projects add.",
130
130
  "error.project_not_registered.cmd": "yf projects scan",
131
+ "error.mobile_turn_unanswered.what": "Il desktop non ha restituito una risposta alla tua richiesta in {minutes} minuti.",
132
+ "error.mobile_turn_unanswered.why": "Il turno puo essere ancora in corso: a scadere e stata l'attesa, non il lavoro. Il desktop non si ferma.",
133
+ "error.mobile_turn_unanswered.fix": "Guarda la chat del desktop: se il turno e finito, la risposta e la. Non rimandare la richiesta senza controllare, altrimenti viene eseguita due volte.",
134
+ "error.mobile_turn_undelivered.what": "Non ho potuto consegnare la tua richiesta al desktop.",
135
+ "error.mobile_turn_undelivered.why": "Il server di chat del desktop non era in ascolto sulla porta {port}. Qui non e stato eseguito nulla.",
136
+ "error.mobile_turn_undelivered.fix": "Apri il pannello Forge sul desktop (o avvialo con yf chat) e rimanda la richiesta.",
137
+ "error.mobile_turn_undelivered.cmd": "yf chat",
131
138
  "panel.button.agents": "Agenti",
132
139
  "panel.agents.title": "Agenti",
133
140
  "panel.agents.subtitle": "Director e sub-agenti registrati in questo progetto",