@nac3/forge-cli 1.23.2 → 1.23.4

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 (36) hide show
  1. package/dist/chat/server.d.ts.map +1 -1
  2. package/dist/chat/server.js +108 -27
  3. package/dist/chat/server.js.map +1 -1
  4. package/dist/core/error_catalog.d.ts +27 -0
  5. package/dist/core/error_catalog.d.ts.map +1 -1
  6. package/dist/core/error_catalog.js +55 -0
  7. package/dist/core/error_catalog.js.map +1 -1
  8. package/dist/core/error_formatter.d.ts +12 -0
  9. package/dist/core/error_formatter.d.ts.map +1 -1
  10. package/dist/core/error_formatter.js +19 -0
  11. package/dist/core/error_formatter.js.map +1 -1
  12. package/dist/relay/command_consumer.d.ts +10 -0
  13. package/dist/relay/command_consumer.d.ts.map +1 -1
  14. package/dist/relay/command_consumer.js +10 -1
  15. package/dist/relay/command_consumer.js.map +1 -1
  16. package/dist/relay/in_flight_turn.d.ts +52 -11
  17. package/dist/relay/in_flight_turn.d.ts.map +1 -1
  18. package/dist/relay/in_flight_turn.js +98 -30
  19. package/dist/relay/in_flight_turn.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/version.d.ts +1 -1
  25. package/dist/version.js +1 -1
  26. package/package.json +1 -1
  27. package/src/i18n/catalogs/ar.json +7 -0
  28. package/src/i18n/catalogs/de.json +7 -0
  29. package/src/i18n/catalogs/en.json +7 -0
  30. package/src/i18n/catalogs/es.json +7 -0
  31. package/src/i18n/catalogs/fr.json +7 -0
  32. package/src/i18n/catalogs/hi.json +7 -0
  33. package/src/i18n/catalogs/it.json +7 -0
  34. package/src/i18n/catalogs/ja.json +7 -0
  35. package/src/i18n/catalogs/pt.json +7 -0
  36. package/src/i18n/catalogs/zh.json +7 -0
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Como el escritorio ejecuta un turno que PIDIO el telefono.
3
+ *
4
+ * El relay no corre nada: deja el pedido en su log y el escritorio lo levanta
5
+ * (command_consumer.ts). Para correrlo, el escritorio hace un POST por
6
+ * loopback a su PROPIO servidor de chat -- el mismo /api/chat que usa el
7
+ * panel -- y espera la respuesta. Esa indireccion es deliberada: un turno que
8
+ * viene del telefono recorre exactamente el mismo camino que uno del panel,
9
+ * sin una segunda implementacion que se desincronice.
10
+ *
11
+ * EL DEFECTO QUE ESTE MODULO CIERRA (PND-234. Pablo, 29-oct-2026, desde el
12
+ * telefono: "No pude completar tu pedido: fetch failed").
13
+ *
14
+ * La respuesta de /api/chat es un JSON, no un stream, asi que sus CABECERAS
15
+ * recien salen cuando el turno entero termino. Con `fetch` sin opciones ese
16
+ * POST hereda el headersTimeout de undici, que es un limite pensado para una
17
+ * llamada corta, y pasado ese punto muere el fetch -- no el turno. El
18
+ * escritorio seguia trabajando y terminaba el trabajo, pero el telefono ya
19
+ * habia recibido "fetch failed" y el usuario quedaba creyendo que no se hizo
20
+ * nada.
21
+ *
22
+ * El limite esta MEDIDO, no estimado: contra un servidor que acepta la
23
+ * conexion y nunca responde, el fetch global de Node 22.16 murio a los
24
+ * 305.677 ms con name=TypeError, message="fetch failed" y
25
+ * cause.code=UND_ERR_HEADERS_TIMEOUT. El turno del reporte habia durado 22
26
+ * minutos (turn_routing.jsonl 13:36:33Z; los archivos que escribio tienen
27
+ * mtime hasta 10:58 local). O sea: cinco minutos de techo para turnos que
28
+ * duran veinte. El defecto es determinista y crece con la utilidad del
29
+ * pedido -- cuanto mas trabajo pide el usuario desde el telefono, mas seguro
30
+ * es que no vea el resultado.
31
+ *
32
+ * POR QUE node:http Y NO fetch. Es la unica forma de mandar los tiempos sin
33
+ * depender de undici: Node lo trae adentro pero no lo expone como paquete, y
34
+ * construir un Agent con otro headersTimeout exigiria declarar una
35
+ * dependencia nueva para algo que el stdlib ya hace. La conexion es loopback
36
+ * y en claro, asi que no se pierde nada por bajar de capa.
37
+ *
38
+ * EL PRESUPUESTO NO DESAPARECE, cambia de escala. Sin ningun limite, un
39
+ * servidor de chat colgado dejaria al consumidor esperando para siempre -- y
40
+ * como atiende un pedido a la vez, ningun pedido POSTERIOR del telefono se
41
+ * correria nunca. Lo que no se usa es `req.setTimeout`, que mide INACTIVIDAD
42
+ * del socket: un turno que piensa diez minutos no manda un byte, y ese
43
+ * temporizador lo mataria sin motivo, que es la forma exacta del bug que esto
44
+ * cierra. Lo que se mide es el tiempo TOTAL, con un techo mas alto que
45
+ * cualquier turno legitimo.
46
+ *
47
+ * Y al vencerse, el usuario recibe algo accionable y VERDADERO: que el
48
+ * escritorio puede seguir trabajando y donde ver el resultado. El mensaje
49
+ * anterior ("no pude completar tu pedido") era falso en el caso mas comun.
50
+ *
51
+ * ASCII puro.
52
+ */
53
+ /**
54
+ * Techo de tiempo total para un turno pedido desde el telefono.
55
+ *
56
+ * Una hora. El numero no sale de la nada: el turno que destapo el defecto
57
+ * duro 22 minutos y termino bien, asi que el techo tiene que estar bastante
58
+ * arriba de eso. Y tiene que seguir siendo finito porque el consumidor
59
+ * atiende de a uno: con el escritorio colgado, este es el tiempo que el
60
+ * telefono queda sin poder pedir nada. Una hora deja pasar cualquier turno
61
+ * real y acota el peor caso a algo que el dueno nota en el dia.
62
+ */
63
+ export declare const MOBILE_TURN_BUDGET_MS: number;
64
+ /** El techo efectivo, con el override de operacion. */
65
+ export declare function mobileTurnBudgetMs(env?: NodeJS.ProcessEnv): number;
66
+ export interface LoopbackResponse {
67
+ status: number;
68
+ body: string;
69
+ }
70
+ /**
71
+ * POST al /api/chat local, esperando lo que tarde el turno.
72
+ *
73
+ * Devuelve el status y el cuerpo crudo; parsear es del llamador, que es el
74
+ * que conoce la forma de la respuesta.
75
+ */
76
+ export declare function postChatTurn(args: {
77
+ port: number;
78
+ payload: Record<string, unknown>;
79
+ budgetMs?: number;
80
+ path?: string;
81
+ }): Promise<LoopbackResponse>;
82
+ //# sourceMappingURL=loopback_turn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loopback_turn.d.ts","sourceRoot":"","sources":["../../src/relay/loopback_turn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAQH;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,QAAc,CAAC;AAEjD,uDAAuD;AACvD,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAU/E;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA6E5B"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Como el escritorio ejecuta un turno que PIDIO el telefono.
3
+ *
4
+ * El relay no corre nada: deja el pedido en su log y el escritorio lo levanta
5
+ * (command_consumer.ts). Para correrlo, el escritorio hace un POST por
6
+ * loopback a su PROPIO servidor de chat -- el mismo /api/chat que usa el
7
+ * panel -- y espera la respuesta. Esa indireccion es deliberada: un turno que
8
+ * viene del telefono recorre exactamente el mismo camino que uno del panel,
9
+ * sin una segunda implementacion que se desincronice.
10
+ *
11
+ * EL DEFECTO QUE ESTE MODULO CIERRA (PND-234. Pablo, 29-oct-2026, desde el
12
+ * telefono: "No pude completar tu pedido: fetch failed").
13
+ *
14
+ * La respuesta de /api/chat es un JSON, no un stream, asi que sus CABECERAS
15
+ * recien salen cuando el turno entero termino. Con `fetch` sin opciones ese
16
+ * POST hereda el headersTimeout de undici, que es un limite pensado para una
17
+ * llamada corta, y pasado ese punto muere el fetch -- no el turno. El
18
+ * escritorio seguia trabajando y terminaba el trabajo, pero el telefono ya
19
+ * habia recibido "fetch failed" y el usuario quedaba creyendo que no se hizo
20
+ * nada.
21
+ *
22
+ * El limite esta MEDIDO, no estimado: contra un servidor que acepta la
23
+ * conexion y nunca responde, el fetch global de Node 22.16 murio a los
24
+ * 305.677 ms con name=TypeError, message="fetch failed" y
25
+ * cause.code=UND_ERR_HEADERS_TIMEOUT. El turno del reporte habia durado 22
26
+ * minutos (turn_routing.jsonl 13:36:33Z; los archivos que escribio tienen
27
+ * mtime hasta 10:58 local). O sea: cinco minutos de techo para turnos que
28
+ * duran veinte. El defecto es determinista y crece con la utilidad del
29
+ * pedido -- cuanto mas trabajo pide el usuario desde el telefono, mas seguro
30
+ * es que no vea el resultado.
31
+ *
32
+ * POR QUE node:http Y NO fetch. Es la unica forma de mandar los tiempos sin
33
+ * depender de undici: Node lo trae adentro pero no lo expone como paquete, y
34
+ * construir un Agent con otro headersTimeout exigiria declarar una
35
+ * dependencia nueva para algo que el stdlib ya hace. La conexion es loopback
36
+ * y en claro, asi que no se pierde nada por bajar de capa.
37
+ *
38
+ * EL PRESUPUESTO NO DESAPARECE, cambia de escala. Sin ningun limite, un
39
+ * servidor de chat colgado dejaria al consumidor esperando para siempre -- y
40
+ * como atiende un pedido a la vez, ningun pedido POSTERIOR del telefono se
41
+ * correria nunca. Lo que no se usa es `req.setTimeout`, que mide INACTIVIDAD
42
+ * del socket: un turno que piensa diez minutos no manda un byte, y ese
43
+ * temporizador lo mataria sin motivo, que es la forma exacta del bug que esto
44
+ * cierra. Lo que se mide es el tiempo TOTAL, con un techo mas alto que
45
+ * cualquier turno legitimo.
46
+ *
47
+ * Y al vencerse, el usuario recibe algo accionable y VERDADERO: que el
48
+ * escritorio puede seguir trabajando y donde ver el resultado. El mensaje
49
+ * anterior ("no pude completar tu pedido") era falso en el caso mas comun.
50
+ *
51
+ * ASCII puro.
52
+ */
53
+ import http from 'node:http';
54
+ import { renderForgeError, ForgeFailure } from '../core/error_catalog.js';
55
+ import { E_MOBILE_TURN_UNANSWERED, E_MOBILE_TURN_UNDELIVERED, } from '../core/error_catalog.js';
56
+ /**
57
+ * Techo de tiempo total para un turno pedido desde el telefono.
58
+ *
59
+ * Una hora. El numero no sale de la nada: el turno que destapo el defecto
60
+ * duro 22 minutos y termino bien, asi que el techo tiene que estar bastante
61
+ * arriba de eso. Y tiene que seguir siendo finito porque el consumidor
62
+ * atiende de a uno: con el escritorio colgado, este es el tiempo que el
63
+ * telefono queda sin poder pedir nada. Una hora deja pasar cualquier turno
64
+ * real y acota el peor caso a algo que el dueno nota en el dia.
65
+ */
66
+ export const MOBILE_TURN_BUDGET_MS = 60 * 60_000;
67
+ /** El techo efectivo, con el override de operacion. */
68
+ export function mobileTurnBudgetMs(env = process.env) {
69
+ const raw = env['YF_MOBILE_TURN_BUDGET_MS'];
70
+ if (raw === undefined || raw === '')
71
+ return MOBILE_TURN_BUDGET_MS;
72
+ const n = Number(raw);
73
+ /* Un valor invalido o no positivo NO apaga la guarda ni la pone en cero:
74
+ * cae al default. Un "0" en una variable de entorno es casi siempre un
75
+ * descuido, y leerlo como "sin limite" convertiria un typo en un
76
+ * consumidor trabado para siempre. */
77
+ if (!Number.isFinite(n) || n <= 0)
78
+ return MOBILE_TURN_BUDGET_MS;
79
+ return n;
80
+ }
81
+ /**
82
+ * POST al /api/chat local, esperando lo que tarde el turno.
83
+ *
84
+ * Devuelve el status y el cuerpo crudo; parsear es del llamador, que es el
85
+ * que conoce la forma de la respuesta.
86
+ */
87
+ export async function postChatTurn(args) {
88
+ const budget = args.budgetMs ?? mobileTurnBudgetMs();
89
+ const body = Buffer.from(JSON.stringify(args.payload), 'utf8');
90
+ const minutes = Math.max(1, Math.round(budget / 60_000));
91
+ return new Promise((resolve, reject) => {
92
+ let settled = false;
93
+ /* Que se vencio el presupuesto se recuerda aparte del error del socket:
94
+ * `req.destroy()` llega al handler de error como un ECONNRESET cualquiera,
95
+ * y sin esta marca el usuario recibiria el mensaje de "no se entrego" --
96
+ * el que dice que no se ejecuto nada -- justamente en el caso en que si se
97
+ * ejecuto. Era el error del que venimos. */
98
+ let vencido = false;
99
+ const req = http.request({
100
+ host: '127.0.0.1',
101
+ port: args.port,
102
+ path: args.path ?? '/api/chat',
103
+ method: 'POST',
104
+ headers: {
105
+ 'content-type': 'application/json',
106
+ 'content-length': String(body.byteLength),
107
+ },
108
+ }, (res) => {
109
+ const chunks = [];
110
+ res.on('data', (c) => chunks.push(c));
111
+ res.on('end', () => {
112
+ if (settled)
113
+ return;
114
+ settled = true;
115
+ clearTimeout(timer);
116
+ resolve({
117
+ status: res.statusCode ?? 0,
118
+ body: Buffer.concat(chunks).toString('utf8'),
119
+ });
120
+ });
121
+ /* Un corte MIENTRAS baja el cuerpo tampoco es "no se entrego": el turno
122
+ * ya corrio y el servidor ya estaba contestando. */
123
+ res.on('error', (e) => fail(e, true));
124
+ });
125
+ const timer = setTimeout(() => {
126
+ vencido = true;
127
+ req.destroy(new Error('presupuesto de turno vencido'));
128
+ }, budget);
129
+ /* Que este temporizador no sea lo que mantiene vivo al proceso. */
130
+ if (typeof timer.unref === 'function') {
131
+ timer.unref();
132
+ }
133
+ const fail = (cause, yaCorrio) => {
134
+ if (settled)
135
+ return;
136
+ settled = true;
137
+ clearTimeout(timer);
138
+ /* "No se entrego" se dice SOLO con prueba positiva de que nada corrio,
139
+ * y la unica prueba positiva es que la conexion no se llego a
140
+ * establecer. Cualquier otro corte -- el socket se cayo despues del
141
+ * saludo, el servidor murio a mitad del turno -- deja abierta la
142
+ * posibilidad de que el turno si haya corrido, y en la duda no se le
143
+ * dice al usuario que no se hizo nada: se le dice que no hubo respuesta
144
+ * y donde mirar. Es la misma doctrina que decidePick e
145
+ * liveBelongsToProject en el lado del telefono: descartar solo con
146
+ * prueba de lo contrario. */
147
+ const noEntrego = !vencido && !yaCorrio && esRechazoDeConexion(cause);
148
+ if (noEntrego) {
149
+ reject(new ForgeFailure(renderForgeError(E_MOBILE_TURN_UNDELIVERED, { port: args.port }), cause));
150
+ return;
151
+ }
152
+ reject(new ForgeFailure(renderForgeError(E_MOBILE_TURN_UNANSWERED, { minutes }), cause));
153
+ };
154
+ req.on('error', (e) => fail(e, false));
155
+ req.end(body);
156
+ });
157
+ }
158
+ /**
159
+ * El socket nunca llego a conectar: no hay servidor escuchando ahi.
160
+ *
161
+ * Es la unica evidencia de que el turno NO corrio. Se mira el errno y no el
162
+ * texto porque el texto cambia entre versiones de Node y entre sistemas.
163
+ */
164
+ function esRechazoDeConexion(e) {
165
+ const code = e?.code;
166
+ if (!code)
167
+ return false;
168
+ return code === 'ECONNREFUSED' || code === 'ENOTFOUND'
169
+ || code === 'EADDRNOTAVAIL' || code === 'EHOSTUNREACH';
170
+ }
171
+ //# sourceMappingURL=loopback_turn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loopback_turn.js","sourceRoot":"","sources":["../../src/relay/loopback_turn.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.2";
5
+ export declare const VERSION = "1.23.4";
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.2';
5
+ export const VERSION = '1.23.4';
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.2",
3
+ "version": "1.23.4",
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>",
@@ -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",
@@ -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": "O verb invocado requer project root ativo mas ~/.yujin-forge/projects.json nao tem entradas.",
129
129
  "error.project_not_registered.fix": "Crie um com yujin.project.init ou registre um existente com yf projects add.",
130
130
  "error.project_not_registered.cmd": "yf projects scan",
131
+ "error.mobile_turn_unanswered.what": "O desktop nao devolveu a resposta do seu pedido em {minutes} minutos.",
132
+ "error.mobile_turn_unanswered.why": "O turno pode continuar rodando: o que expirou foi a espera, nao o trabalho. O desktop nao para.",
133
+ "error.mobile_turn_unanswered.fix": "Veja o chat do desktop: se o turno terminou, a resposta esta la. Nao reenvie o pedido sem olhar, ou ele roda duas vezes.",
134
+ "error.mobile_turn_undelivered.what": "Nao consegui entregar seu pedido ao desktop.",
135
+ "error.mobile_turn_undelivered.why": "O servidor de chat do desktop nao estava escutando na porta {port}. Aqui nada foi executado.",
136
+ "error.mobile_turn_undelivered.fix": "Abra o painel do Forge no desktop (ou inicie com yf chat) e envie o pedido de novo.",
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 e sub-agentes registados neste projeto",
@@ -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": "本项目已注册的总监和子智能体",