@nac3/forge-cli 1.23.4 → 1.23.6

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 (77) hide show
  1. package/dist/bin/yf.d.ts.map +1 -1
  2. package/dist/bin/yf.js +2 -0
  3. package/dist/bin/yf.js.map +1 -1
  4. package/dist/chat/doctrine_digest.d.ts.map +1 -1
  5. package/dist/chat/doctrine_digest.js +4 -1
  6. package/dist/chat/doctrine_digest.js.map +1 -1
  7. package/dist/chat/tools/evidence.d.ts +34 -2
  8. package/dist/chat/tools/evidence.d.ts.map +1 -1
  9. package/dist/chat/tools/evidence.js +90 -12
  10. package/dist/chat/tools/evidence.js.map +1 -1
  11. package/dist/commands/doctor.d.ts.map +1 -1
  12. package/dist/commands/doctor.js +62 -0
  13. package/dist/commands/doctor.js.map +1 -1
  14. package/dist/commands/temp.d.ts +36 -0
  15. package/dist/commands/temp.d.ts.map +1 -0
  16. package/dist/commands/temp.js +83 -0
  17. package/dist/commands/temp.js.map +1 -0
  18. package/dist/commands/urazuke.d.ts.map +1 -1
  19. package/dist/commands/urazuke.js +27 -0
  20. package/dist/commands/urazuke.js.map +1 -1
  21. package/dist/core/error_catalog.d.ts +4 -0
  22. package/dist/core/error_catalog.d.ts.map +1 -1
  23. package/dist/core/error_catalog.js +16 -0
  24. package/dist/core/error_catalog.js.map +1 -1
  25. package/dist/core/loopback_post.d.ts +101 -0
  26. package/dist/core/loopback_post.d.ts.map +1 -0
  27. package/dist/core/loopback_post.js +156 -0
  28. package/dist/core/loopback_post.js.map +1 -0
  29. package/dist/core/temp_janitor.d.ts +83 -0
  30. package/dist/core/temp_janitor.d.ts.map +1 -0
  31. package/dist/core/temp_janitor.js +160 -0
  32. package/dist/core/temp_janitor.js.map +1 -0
  33. package/dist/docs/doctrine/urazuke.md +50 -38
  34. package/dist/docs/doctrine/yf-commands.md +2 -0
  35. package/dist/mcp/forge_panel_server.d.ts +1 -26
  36. package/dist/mcp/forge_panel_server.d.ts.map +1 -1
  37. package/dist/mcp/forge_panel_server.js +5 -26
  38. package/dist/mcp/forge_panel_server.js.map +1 -1
  39. package/dist/mcp/forge_verbs_server.d.ts +1 -11
  40. package/dist/mcp/forge_verbs_server.d.ts.map +1 -1
  41. package/dist/mcp/forge_verbs_server.js +7 -23
  42. package/dist/mcp/forge_verbs_server.js.map +1 -1
  43. package/dist/mcp/panel_invoke.d.ts +51 -0
  44. package/dist/mcp/panel_invoke.d.ts.map +1 -0
  45. package/dist/mcp/panel_invoke.js +102 -0
  46. package/dist/mcp/panel_invoke.js.map +1 -0
  47. package/dist/nac3/internal_manifest.d.ts +2 -0
  48. package/dist/nac3/internal_manifest.d.ts.map +1 -1
  49. package/dist/nac3/internal_manifest.js +18 -3
  50. package/dist/nac3/internal_manifest.js.map +1 -1
  51. package/dist/nac3/verb_budget.d.ts +110 -0
  52. package/dist/nac3/verb_budget.d.ts.map +1 -0
  53. package/dist/nac3/verb_budget.js +142 -0
  54. package/dist/nac3/verb_budget.js.map +1 -0
  55. package/dist/relay/loopback_turn.d.ts +15 -42
  56. package/dist/relay/loopback_turn.d.ts.map +1 -1
  57. package/dist/relay/loopback_turn.js +27 -115
  58. package/dist/relay/loopback_turn.js.map +1 -1
  59. package/dist/urazuke/evidence.d.ts +22 -0
  60. package/dist/urazuke/evidence.d.ts.map +1 -1
  61. package/dist/urazuke/evidence.js +42 -3
  62. package/dist/urazuke/evidence.js.map +1 -1
  63. package/dist/version.d.ts +1 -1
  64. package/dist/version.js +1 -1
  65. package/docs/doctrine/urazuke.md +50 -38
  66. package/docs/doctrine/yf-commands.md +2 -0
  67. package/package.json +1 -1
  68. package/src/i18n/catalogs/ar.json +3 -0
  69. package/src/i18n/catalogs/de.json +3 -0
  70. package/src/i18n/catalogs/en.json +3 -0
  71. package/src/i18n/catalogs/es.json +3 -0
  72. package/src/i18n/catalogs/fr.json +3 -0
  73. package/src/i18n/catalogs/hi.json +3 -0
  74. package/src/i18n/catalogs/it.json +3 -0
  75. package/src/i18n/catalogs/ja.json +3 -0
  76. package/src/i18n/catalogs/pt.json +3 -0
  77. package/src/i18n/catalogs/zh.json +3 -0
@@ -0,0 +1,156 @@
1
+ /**
2
+ * El POST por loopback que dura lo que dura el trabajo.
3
+ *
4
+ * Forge habla consigo mismo por HTTP en 127.0.0.1 en dos lugares distintos y
5
+ * por el mismo motivo: el que pide no comparte memoria con el que ejecuta.
6
+ *
7
+ * - El consumidor de pedidos del telefono POSTea a su propio /api/chat
8
+ * (relay/loopback_turn.ts).
9
+ * - Los dos servers MCP -- nietos de Forge, lanzados por `claude -p` --
10
+ * POSTean cada invocacion de verbo a /api/forge/panel-invoke
11
+ * (mcp/forge_verbs_server.ts, mcp/forge_panel_server.ts).
12
+ *
13
+ * Las dos respuestas son un JSON que recien se arma cuando el trabajo entero
14
+ * termino, asi que sus CABECERAS no salen antes. Con `fetch` sin opciones ese
15
+ * POST hereda el headersTimeout de undici, un limite pensado para una llamada
16
+ * corta, y pasado ese punto muere el fetch -- no el trabajo. El servidor sigue
17
+ * trabajando y termina; el que esperaba ya recibio "fetch failed".
18
+ *
19
+ * EL LIMITE ESTA MEDIDO, NO ESTIMADO: contra un servidor que acepta la
20
+ * conexion y nunca responde, el fetch global de Node 22.16 murio a los
21
+ * 305.677 ms con name=TypeError, message="fetch failed" y
22
+ * cause.code=UND_ERR_HEADERS_TIMEOUT.
23
+ *
24
+ * El defecto se arreglo primero en el camino del telefono (PND-234) y volvio a
25
+ * aparecer, identico, en el camino de los verbos (PND-235): el mismo techo de
26
+ * cinco minutos sobre `yujin.evidence.run`, que es justo el verbo que acredita
27
+ * una bateria de siete minutos. Un arreglo que no se comparte se vuelve a
28
+ * pagar, asi que el transporte vive aca y los dos lo usan.
29
+ *
30
+ * POR QUE node:http Y NO fetch. Es la unica forma de mandar los tiempos sin
31
+ * depender de undici: Node lo trae adentro pero no lo expone como paquete, y
32
+ * construir un Agent con otro headersTimeout exigiria declarar una dependencia
33
+ * nueva para algo que el stdlib ya hace. La conexion es loopback y en claro,
34
+ * asi que no se pierde nada por bajar de capa.
35
+ *
36
+ * EL PRESUPUESTO NO DESAPARECE, cambia de escala -- y lo fija el LLAMADOR,
37
+ * porque el unico que sabe cuanto puede durar legitimamente el trabajo es el
38
+ * que lo pidio. Lo que no se usa es `req.setTimeout`, que mide INACTIVIDAD del
39
+ * socket: un trabajo que piensa diez minutos no manda un byte, y ese
40
+ * temporizador lo mataria sin motivo, que es la forma exacta del bug que esto
41
+ * cierra. Lo que se mide es el tiempo TOTAL.
42
+ *
43
+ * ASCII puro.
44
+ */
45
+ import http from 'node:http';
46
+ /** Piso del presupuesto: ningun POST por loopback se corta antes de esto. */
47
+ export const LOOPBACK_MIN_BUDGET_MS = 30_000;
48
+ /** El corte, con lo que el llamador necesita para redactar su propio mensaje
49
+ * (cada camino tiene su catalogo de errores y su idioma). */
50
+ export class LoopbackCut extends Error {
51
+ kind;
52
+ /** Se vencio el presupuesto (y no: el socket se cayo por su cuenta). */
53
+ expired;
54
+ budget_ms;
55
+ elapsed_ms;
56
+ constructor(kind, args) {
57
+ super('loopback ' + kind + (args.expired ? ' (presupuesto de ' + args.budgetMs + ' ms vencido)' : ''), args.cause === undefined ? undefined : { cause: args.cause });
58
+ this.name = 'LoopbackCut';
59
+ this.kind = kind;
60
+ this.expired = args.expired;
61
+ this.budget_ms = args.budgetMs;
62
+ this.elapsed_ms = args.elapsedMs;
63
+ }
64
+ }
65
+ /**
66
+ * El socket nunca llego a conectar: no hay servidor escuchando ahi.
67
+ *
68
+ * Es la unica evidencia de que el trabajo NO corrio. Se mira el errno y no el
69
+ * texto porque el texto cambia entre versiones de Node y entre sistemas.
70
+ */
71
+ export function isConnectionRefusal(e) {
72
+ const code = e?.code;
73
+ if (!code)
74
+ return false;
75
+ return code === 'ECONNREFUSED' || code === 'ENOTFOUND'
76
+ || code === 'EADDRNOTAVAIL' || code === 'EHOSTUNREACH';
77
+ }
78
+ /**
79
+ * POST de un JSON al loopback, esperando lo que tarde.
80
+ *
81
+ * Devuelve el status y el cuerpo crudo; parsear es del llamador, que es el
82
+ * unico que conoce la forma de la respuesta. Un status que no es 200 NO es una
83
+ * excepcion: esconderlo seria esconder el dato que permite diagnosticarlo.
84
+ */
85
+ export async function postLoopbackJson(args) {
86
+ const body = Buffer.from(JSON.stringify(args.payload), 'utf8');
87
+ const arranco = Date.now();
88
+ /* Un presupuesto en cero, negativo o no numerico NO se obedece: se cae al
89
+ * piso. Obedecerlo seria matar la conexion antes de abrirla -- cada
90
+ * invocacion fallaria al instante y el sintoma (todo falla, siempre) no se
91
+ * parece en nada a la causa (un numero mal calculado un modulo mas arriba).
92
+ * Es la misma decision que `mobileTurnBudgetMs` toma con su variable de
93
+ * entorno: un cero en un numero de configuracion es casi siempre un
94
+ * descuido. */
95
+ const budget = Number.isFinite(args.budgetMs) && args.budgetMs > 0
96
+ ? args.budgetMs : LOOPBACK_MIN_BUDGET_MS;
97
+ return new Promise((resolve, reject) => {
98
+ let settled = false;
99
+ /* Que se vencio el presupuesto se recuerda aparte del error del socket:
100
+ * `req.destroy()` llega al handler de error como un ECONNRESET cualquiera,
101
+ * y sin esta marca el vencimiento se clasificaria como "no se entrego" --
102
+ * el caso que afirma que no corrio nada -- justamente cuando si corrio. */
103
+ let vencido = false;
104
+ const req = http.request({
105
+ host: args.host ?? '127.0.0.1',
106
+ port: args.port,
107
+ path: args.path,
108
+ method: 'POST',
109
+ headers: {
110
+ 'content-type': 'application/json',
111
+ 'content-length': String(body.byteLength),
112
+ ...(args.headers ?? {}),
113
+ },
114
+ }, (res) => {
115
+ const chunks = [];
116
+ res.on('data', (c) => chunks.push(c));
117
+ res.on('end', () => {
118
+ if (settled)
119
+ return;
120
+ settled = true;
121
+ clearTimeout(timer);
122
+ resolve({
123
+ status: res.statusCode ?? 0,
124
+ body: Buffer.concat(chunks).toString('utf8'),
125
+ });
126
+ });
127
+ /* Un corte MIENTRAS baja el cuerpo tampoco es "no se entrego": el
128
+ * trabajo ya corrio y el servidor ya estaba contestando. */
129
+ res.on('error', (e) => fail(e, true));
130
+ });
131
+ const timer = setTimeout(() => {
132
+ vencido = true;
133
+ req.destroy(new Error('presupuesto de loopback vencido'));
134
+ }, budget);
135
+ /* Que este temporizador no sea lo que mantiene vivo al proceso. */
136
+ if (typeof timer.unref === 'function') {
137
+ timer.unref();
138
+ }
139
+ const fail = (cause, yaCorrio) => {
140
+ if (settled)
141
+ return;
142
+ settled = true;
143
+ clearTimeout(timer);
144
+ const noEntrego = !vencido && !yaCorrio && isConnectionRefusal(cause);
145
+ reject(new LoopbackCut(noEntrego ? 'undelivered' : 'unanswered', {
146
+ expired: vencido,
147
+ budgetMs: budget,
148
+ elapsedMs: Date.now() - arranco,
149
+ cause,
150
+ }));
151
+ };
152
+ req.on('error', (e) => fail(e, false));
153
+ req.end(body);
154
+ });
155
+ }
156
+ //# sourceMappingURL=loopback_post.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loopback_post.js","sourceRoot":"","sources":["../../src/core/loopback_post.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /** Prefijo del padre por corrida que instala el cajon de arena. */
2
+ export declare const SANDBOX_PREFIX = "yf-run-";
3
+ /** Edad minima por defecto para considerar huerfano a un temporal: 2 h.
4
+ *
5
+ * No es cosmetico. En esta maquina casi siempre hay OTRA bateria corriendo
6
+ * al lado (y cuatro paneles vivos), asi que borrar por nombre sin mirar la
7
+ * edad mata la corrida del vecino -- el riesgo que el propio PND-241 pide
8
+ * evitar. Una bateria completa tarda ~10 min medidos; 2 h deja doce veces
9
+ * ese margen. */
10
+ export declare const DEFAULT_MIN_AGE_MS: number;
11
+ /** Edad a la que el cajon de arena considera abandonado un padre de otra
12
+ * corrida (la suya la borra por nombre, no por edad). */
13
+ export declare const STALE_SANDBOX_MS: number;
14
+ export interface TempEntry {
15
+ name: string;
16
+ path: string;
17
+ mtimeMs: number;
18
+ /** true si es un padre por corrida (yf-run-*), no un temporal suelto. */
19
+ sandbox: boolean;
20
+ }
21
+ export interface SweepOptions {
22
+ /** Donde buscar. Por defecto el %TEMP% real. */
23
+ tmpRoot?: string;
24
+ /** Reloj, inyectable para los tests. */
25
+ now?: number;
26
+ /** Solo se borra lo mas viejo que esto. */
27
+ minAgeMs?: number;
28
+ /** Contar sin borrar. */
29
+ dryRun?: boolean;
30
+ /** Nombres (no caminos) que no hay que tocar nunca. */
31
+ keep?: readonly string[];
32
+ }
33
+ export interface SweepResult {
34
+ tmpRoot: string;
35
+ /** Temporales de Forge encontrados. */
36
+ scanned: number;
37
+ /** Candidatos por edad. */
38
+ eligible: number;
39
+ /** Borrados de verdad (0 en dryRun). */
40
+ removed: number;
41
+ /** Se intento y no se pudo -- tipicamente un escritor vivo. */
42
+ failed: {
43
+ name: string;
44
+ error: string;
45
+ }[];
46
+ /** Salteados por ser demasiado recientes (posible corrida viva). */
47
+ skippedFresh: number;
48
+ /** Salteados porque los pidio `keep`. */
49
+ skippedKept: number;
50
+ }
51
+ /**
52
+ * La regla de que cuenta como temporal de Forge, en un solo lugar.
53
+ *
54
+ * Deliberadamente ANCLADA al arranque: `startsWith('yf-')` y no un
55
+ * `includes`, para no barrer el temporal de otra herramienta que mencione
56
+ * yf- en el medio de su nombre.
57
+ */
58
+ export declare function isForgeTempName(name: string): boolean;
59
+ /** Nombre del padre por corrida. Lleva pid + reloj + azar para que dos
60
+ * baterias simultaneas no compartan cajon. */
61
+ export declare function newSandboxName(pid: number, now: number, rand?: number): string;
62
+ /**
63
+ * Cuenta los nombres `yf-*` de `tmpRoot` SIN hacer un stat por cada uno.
64
+ *
65
+ * Existe por costo: `listForgeTempDirs` hace un stat por entrada para poder
66
+ * mirar la edad, y en la maquina donde se abrio PND-241 eso eran 26.034
67
+ * stats. Un comando de diagnostico no puede pagar eso para decir "hay
68
+ * mucho". El que necesita la edad usa la otra; el que solo necesita el
69
+ * tamano del stock usa esta.
70
+ */
71
+ export declare function countForgeTempNames(tmpRoot?: string): Promise<number>;
72
+ /** Lista los temporales de Forge que hay en `tmpRoot`. */
73
+ export declare function listForgeTempDirs(tmpRoot?: string): Promise<TempEntry[]>;
74
+ /**
75
+ * Barre los temporales de Forge huerfanos.
76
+ *
77
+ * Fail-open a proposito: un directorio que no se puede borrar (escritor
78
+ * vivo, permiso) se anota en `failed` y el barrido SIGUE. Un portero que
79
+ * aborta en el primer EBUSY deja el resto del stock en pie, que es
80
+ * exactamente el estado del que venimos.
81
+ */
82
+ export declare function sweepForgeTemp(opts?: SweepOptions): Promise<SweepResult>;
83
+ //# sourceMappingURL=temp_janitor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temp_janitor.d.ts","sourceRoot":"","sources":["../../src/core/temp_janitor.ts"],"names":[],"mappings":"AAuCA,mEAAmE;AACnE,eAAO,MAAM,cAAc,YAAY,CAAC;AAExC;;;;;;iBAMiB;AACjB,eAAO,MAAM,kBAAkB,QAAqB,CAAC;AAErD;yDACyD;AACzD,eAAO,MAAM,gBAAgB,QAAqB,CAAC;AAEnD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yBAAyB;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uDAAuD;IACvD,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1C,oEAAoE;IACpE,YAAY,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;8CAC8C;AAC9C,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,SAAgB,GAAG,MAAM,CAGrF;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,SAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAOhF;AAED,0DAA0D;AAC1D,wBAAsB,iBAAiB,CAAC,OAAO,SAAc,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAuBnF;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAoClF"}
@@ -0,0 +1,160 @@
1
+ /**
2
+ * El portero de %TEMP%: cuenta y barre los directorios temporales que deja
3
+ * la bateria (PND-241).
4
+ *
5
+ * MEDIDO el 31-oct-2026 en C:\Users\ASUS\AppData\Local\Temp: 26.034
6
+ * directorios yf-* huerfanos, sobre 47.484 entradas en total. La nota del
7
+ * commit 5f30f42 habia contado 5.905 nueve dias antes, asi que el stock
8
+ * crece con cada corrida y nadie lo limpia.
9
+ *
10
+ * Y la causa NO es que los tests no limpien. Los grandes aportantes SI
11
+ * tienen su afterEach con `fs.rm(tmpHome, {recursive, force, maxRetries})`,
12
+ * y la bateria pasa en verde -- si ese rm tirara, el hook fallaria. Lo que
13
+ * se midio al correr tests/vault-server.test.ts aislado (17 casos, 8
14
+ * directorios nuevos) es que lo que queda en pie contiene EXACTAMENTE esto:
15
+ *
16
+ * yf-vsrv-home-BqVTGW/AppData/Roaming <- y nada mas
17
+ *
18
+ * O sea: el rm borro el arbol y DESPUES alguien volvio a crear el camino,
19
+ * ya con el HOME del test restaurado. Es la forma de PND-237 otra vez: un
20
+ * escritor que sobrevive al cierre. Perseguir ese escritor en cada uno de
21
+ * los 230 archivos que hacen mkdtemp es la via larga y se vuelve a filtrar
22
+ * con el proximo test que se escriba.
23
+ *
24
+ * La via corta es cambiar DONDE caen: la bateria corre con su propio
25
+ * os.tmpdir() -- un unico padre yf-run-<pid>-<t> dentro del %TEMP% real --
26
+ * y al terminar se borra el padre entero. Un escritor rezagado que recrea
27
+ * su camino lo recrea ADENTRO del padre, asi que igual se va. Ver
28
+ * tests/global_temp_sandbox.ts, que es el que lo instala.
29
+ *
30
+ * Este modulo tiene las dos mitades y las comparten TRES consumidores (el
31
+ * cajon de arena de la bateria, `yf temp`, y el chequeo del doctor), para
32
+ * que la regla de que es "un temporal de Forge" viva en un solo lugar.
33
+ *
34
+ * ASCII puro.
35
+ */
36
+ import { promises as fs } from 'node:fs';
37
+ import os from 'node:os';
38
+ import path from 'node:path';
39
+ /** Prefijo del padre por corrida que instala el cajon de arena. */
40
+ export const SANDBOX_PREFIX = 'yf-run-';
41
+ /** Edad minima por defecto para considerar huerfano a un temporal: 2 h.
42
+ *
43
+ * No es cosmetico. En esta maquina casi siempre hay OTRA bateria corriendo
44
+ * al lado (y cuatro paneles vivos), asi que borrar por nombre sin mirar la
45
+ * edad mata la corrida del vecino -- el riesgo que el propio PND-241 pide
46
+ * evitar. Una bateria completa tarda ~10 min medidos; 2 h deja doce veces
47
+ * ese margen. */
48
+ export const DEFAULT_MIN_AGE_MS = 2 * 60 * 60 * 1000;
49
+ /** Edad a la que el cajon de arena considera abandonado un padre de otra
50
+ * corrida (la suya la borra por nombre, no por edad). */
51
+ export const STALE_SANDBOX_MS = 6 * 60 * 60 * 1000;
52
+ /**
53
+ * La regla de que cuenta como temporal de Forge, en un solo lugar.
54
+ *
55
+ * Deliberadamente ANCLADA al arranque: `startsWith('yf-')` y no un
56
+ * `includes`, para no barrer el temporal de otra herramienta que mencione
57
+ * yf- en el medio de su nombre.
58
+ */
59
+ export function isForgeTempName(name) {
60
+ return name.startsWith('yf-');
61
+ }
62
+ /** Nombre del padre por corrida. Lleva pid + reloj + azar para que dos
63
+ * baterias simultaneas no compartan cajon. */
64
+ export function newSandboxName(pid, now, rand = Math.random()) {
65
+ const salt = Math.floor(rand * 0xffffff).toString(36).padStart(4, '0');
66
+ return SANDBOX_PREFIX + pid + '-' + now.toString(36) + '-' + salt;
67
+ }
68
+ /**
69
+ * Cuenta los nombres `yf-*` de `tmpRoot` SIN hacer un stat por cada uno.
70
+ *
71
+ * Existe por costo: `listForgeTempDirs` hace un stat por entrada para poder
72
+ * mirar la edad, y en la maquina donde se abrio PND-241 eso eran 26.034
73
+ * stats. Un comando de diagnostico no puede pagar eso para decir "hay
74
+ * mucho". El que necesita la edad usa la otra; el que solo necesita el
75
+ * tamano del stock usa esta.
76
+ */
77
+ export async function countForgeTempNames(tmpRoot = os.tmpdir()) {
78
+ try {
79
+ const names = await fs.readdir(tmpRoot);
80
+ return names.filter(isForgeTempName).length;
81
+ }
82
+ catch {
83
+ return 0;
84
+ }
85
+ }
86
+ /** Lista los temporales de Forge que hay en `tmpRoot`. */
87
+ export async function listForgeTempDirs(tmpRoot = os.tmpdir()) {
88
+ let names;
89
+ try {
90
+ names = await fs.readdir(tmpRoot);
91
+ }
92
+ catch {
93
+ return [];
94
+ }
95
+ const out = [];
96
+ for (const name of names) {
97
+ if (!isForgeTempName(name))
98
+ continue;
99
+ const full = path.join(tmpRoot, name);
100
+ let mtimeMs = 0;
101
+ try {
102
+ const st = await fs.stat(full);
103
+ if (!st.isDirectory())
104
+ continue;
105
+ mtimeMs = st.mtimeMs;
106
+ }
107
+ catch {
108
+ /* Desaparecio entre el readdir y el stat: lo limpio alguien mas. */
109
+ continue;
110
+ }
111
+ out.push({ name, path: full, mtimeMs, sandbox: name.startsWith(SANDBOX_PREFIX) });
112
+ }
113
+ return out;
114
+ }
115
+ /**
116
+ * Barre los temporales de Forge huerfanos.
117
+ *
118
+ * Fail-open a proposito: un directorio que no se puede borrar (escritor
119
+ * vivo, permiso) se anota en `failed` y el barrido SIGUE. Un portero que
120
+ * aborta en el primer EBUSY deja el resto del stock en pie, que es
121
+ * exactamente el estado del que venimos.
122
+ */
123
+ export async function sweepForgeTemp(opts = {}) {
124
+ const tmpRoot = opts.tmpRoot ?? os.tmpdir();
125
+ const now = opts.now ?? Date.now();
126
+ const minAgeMs = opts.minAgeMs ?? DEFAULT_MIN_AGE_MS;
127
+ const keep = new Set(opts.keep ?? []);
128
+ const entries = await listForgeTempDirs(tmpRoot);
129
+ const res = {
130
+ tmpRoot,
131
+ scanned: entries.length,
132
+ eligible: 0,
133
+ removed: 0,
134
+ failed: [],
135
+ skippedFresh: 0,
136
+ skippedKept: 0,
137
+ };
138
+ for (const e of entries) {
139
+ if (keep.has(e.name)) {
140
+ res.skippedKept++;
141
+ continue;
142
+ }
143
+ if (now - e.mtimeMs < minAgeMs) {
144
+ res.skippedFresh++;
145
+ continue;
146
+ }
147
+ res.eligible++;
148
+ if (opts.dryRun)
149
+ continue;
150
+ try {
151
+ await fs.rm(e.path, { recursive: true, force: true, maxRetries: 3, retryDelay: 50 });
152
+ res.removed++;
153
+ }
154
+ catch (err) {
155
+ res.failed.push({ name: e.name, error: err instanceof Error ? err.message : String(err) });
156
+ }
157
+ }
158
+ return res;
159
+ }
160
+ //# sourceMappingURL=temp_janitor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temp_janitor.js","sourceRoot":"","sources":["../../src/core/temp_janitor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,mEAAmE;AACnE,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC;AAExC;;;;;;iBAMiB;AACjB,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAErD;yDACyD;AACzD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAuCnD;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC;AAED;8CAC8C;AAC9C,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,GAAW,EAAE,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE;IAC3E,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACvE,OAAO,cAAc,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC;AACpE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAO,GAAG,EAAE,CAAC,MAAM,EAAE;IAC7D,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACxC,OAAO,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED,0DAA0D;AAC1D,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAO,GAAG,EAAE,CAAC,MAAM,EAAE;IAC3D,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;YAAE,SAAS;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACtC,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE;gBAAE,SAAS;YAChC,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,oEAAoE;YACpE,SAAS;QACX,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAqB,EAAE;IAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;IAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;IACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,kBAAkB,CAAC;IACrD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAEtC,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,GAAG,GAAgB;QACvB,OAAO;QACP,OAAO,EAAE,OAAO,CAAC,MAAM;QACvB,QAAQ,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,EAAE;QACV,YAAY,EAAE,CAAC;QACf,WAAW,EAAE,CAAC;KACf,CAAC;IAEF,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YACrB,GAAG,CAAC,WAAW,EAAE,CAAC;YAClB,SAAS;QACX,CAAC;QACD,IAAI,GAAG,GAAG,CAAC,CAAC,OAAO,GAAG,QAAQ,EAAE,CAAC;YAC/B,GAAG,CAAC,YAAY,EAAE,CAAC;YACnB,SAAS;QACX,CAAC;QACD,GAAG,CAAC,QAAQ,EAAE,CAAC;QACf,IAAI,IAAI,CAAC,MAAM;YAAE,SAAS;QAC1B,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;YACrF,GAAG,CAAC,OAAO,EAAE,CAAC;QAChB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7F,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -1,38 +1,50 @@
1
- # Urazuke -- the evidence method, as Forge runs it
2
-
3
- Urazuke (github.com/pkuschnirof/urazuke) is the method behind every project
4
- Forge builds or maintains: 24 ordered steps in four stretches, each with an
5
- exact prompt, the inputs the owner prepares, the artifacts the agent leaves
6
- in the repository, and a completion check the owner does WITHOUT reading
7
- code. An existing system built without it goes through eight normalisation
8
- stations (N0..N7) first and enters the loop at step 5.
9
-
10
- ## What is mechanical (not prose)
11
-
12
- - The project's workflow is `urazuke` (no code) or `urazuke-legacy` (code
13
- without the method's artifacts). Every canonical task carries its step.
14
- - The CURRENT step's prompt is injected into your system prompt every turn,
15
- with the state of its checks (section "URAZUKE -- peldano NN"). Act on
16
- that prompt as if the owner had pasted it. Do not skip ahead.
17
- - A canonical task closes ONLY when `evaluateStep()` is GREEN: the files
18
- the step names exist, are not stubs, say what they must; the sizing
19
- record is admissible (G9); the plan items carry a spec; the evidence
20
- receipts exist. `yujin.pending.close` refuses a red step. An override
21
- needs the OWNER's written `force_reason` (kept in history); never pass
22
- one on your own initiative.
23
- - Evidence is a RECEIPT Forge records (command, ref, exit code, counts),
24
- never your summary. "Tests pass" without a receipt is a claim.
25
-
26
- ## How to work inside it
27
-
28
- 1. Read the URAZUKE section: red checks are what is missing. Produce the
29
- artifact at the path named, with real content, or ask the owner for the
30
- input that is theirs (`antes de enviar`). Never invent an owner input.
31
- 2. When the section says GREEN, close the task with `yujin.pending.close`
32
- (full expediente) and the next step's prompt arrives on the next turn.
33
- 3. `yujin.urazuke.status` shows the whole ladder; `yujin.urazuke.step`
34
- shows any step in full (prompts, inputs, artifacts, checklist).
35
- 4. The plan is the pendings: each item needs `spec` (acceptance "given /
36
- when / then" + `how_verified`) before it is implemented (step 5).
37
- 5. No deadlines, ever: the method fixes the order and the gates, not the
38
- calendar. Speed is a consequence, not the objective.
1
+ # Urazuke -- the evidence method, as Forge runs it
2
+
3
+ Urazuke (github.com/pkuschnirof/urazuke) is the method behind every project
4
+ Forge builds or maintains: 24 ordered steps in four stretches, each with an
5
+ exact prompt, the inputs the owner prepares, the artifacts the agent leaves
6
+ in the repository, and a completion check the owner does WITHOUT reading
7
+ code. An existing system built without it goes through eight normalisation
8
+ stations (N0..N7) first and enters the loop at step 5.
9
+
10
+ ## What is mechanical (not prose)
11
+
12
+ - The project's workflow is `urazuke` (no code) or `urazuke-legacy` (code
13
+ without the method's artifacts). Every canonical task carries its step.
14
+ - The CURRENT step's prompt is injected into your system prompt every turn,
15
+ with the state of its checks (section "URAZUKE -- peldano NN"). Act on
16
+ that prompt as if the owner had pasted it. Do not skip ahead.
17
+ - A canonical task closes ONLY when `evaluateStep()` is GREEN: the files
18
+ the step names exist, are not stubs, say what they must; the sizing
19
+ record is admissible (G9); the plan items carry a spec; the evidence
20
+ receipts exist. `yujin.pending.close` refuses a red step. An override
21
+ needs the OWNER's written `force_reason` (kept in history); never pass
22
+ one on your own initiative.
23
+ - Evidence is a RECEIPT Forge records (command, ref, exit code, counts),
24
+ never your summary. "Tests pass" without a receipt is a claim.
25
+ - A LONG run leaves its receipt the same way. `yujin.evidence.run` blocks
26
+ the turn only while the run fits the blocking window (10 min, lowered with
27
+ `limits.claude_cli_silence_ms`); over that, or with `background: true`, it
28
+ is launched detached and returns a HANDLE. That is not a degraded mode:
29
+ the receipt is written by whoever runs, not by whoever waits. Read it with
30
+ `yujin.evidence.list` when the task finishes (`yujin.task.status({id})`
31
+ for the progress). Do NOT relaunch a run that already has a handle.
32
+ - And the corollary for any invocation that dies waiting: a verb call that
33
+ comes back UNANSWERED (E_VERB_CALL_UNANSWERED) did not necessarily fail.
34
+ Before redoing the work, LOOK FOR THE TRACE -- `yujin.evidence.list` for a
35
+ receipt, `yujin.task.list` for a task. Two closes were reported as
36
+ "believed" over a receipt that existed on disk the whole time.
37
+
38
+ ## How to work inside it
39
+
40
+ 1. Read the URAZUKE section: red checks are what is missing. Produce the
41
+ artifact at the path named, with real content, or ask the owner for the
42
+ input that is theirs (`antes de enviar`). Never invent an owner input.
43
+ 2. When the section says GREEN, close the task with `yujin.pending.close`
44
+ (full expediente) and the next step's prompt arrives on the next turn.
45
+ 3. `yujin.urazuke.status` shows the whole ladder; `yujin.urazuke.step`
46
+ shows any step in full (prompts, inputs, artifacts, checklist).
47
+ 4. The plan is the pendings: each item needs `spec` (acceptance "given /
48
+ when / then" + `how_verified`) before it is implemented (step 5).
49
+ 5. No deadlines, ever: the method fixes the order and the gates, not the
50
+ calendar. Speed is a consequence, not the objective.
@@ -35,6 +35,8 @@ SHIP + DEPLOY
35
35
  OBSERVABILITY
36
36
  yf log per-scope log levels + redaction (SQ.K)
37
37
  yf projects cross-device project registry
38
+ yf task background tasks (list / status / log / stop)
39
+ yf temp orphan temp dirs: status (count) / clean (delete)
38
40
 
39
41
  QA HARNESSES
40
42
  yf qa brain-matrix E2E test invariants against LLM brains
@@ -17,30 +17,5 @@
17
17
  * Hand-rolled JSON-RPC 2.0 sobre stdio (estilo zero-dep del repo,
18
18
  * espejo del cliente en protocol_client.ts). ASCII-only.
19
19
  */
20
- interface JsonRpcReq {
21
- jsonrpc: '2.0';
22
- id?: number | string;
23
- method: string;
24
- params?: {
25
- name?: string;
26
- arguments?: Record<string, unknown>;
27
- };
28
- }
29
- interface ToolDef {
30
- name: string;
31
- description: string;
32
- inputSchema: Record<string, unknown>;
33
- }
34
- declare const TOOLS: ToolDef[];
35
- declare function send(msg: unknown): void;
36
- declare function logErr(msg: string): void;
37
- /** Reenvia un nac3_invoke al chat server (que corre el dispatcher
38
- * real) y devuelve el texto del resultado. */
39
- declare function forwardInvoke(verbId: string, args: Record<string, unknown>): Promise<{
40
- ok: boolean;
41
- text: string;
42
- }>;
43
- declare function toolResult(id: number | string | undefined, text: string, isError?: boolean): void;
44
- declare function handle(req: JsonRpcReq): Promise<void>;
45
- declare function main(): void;
20
+ export {};
46
21
  //# sourceMappingURL=forge_panel_server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"forge_panel_server.d.ts","sourceRoot":"","sources":["../../src/mcp/forge_panel_server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,UAAU,UAAU;IAClB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;CACjE;AAED,UAAU,OAAO;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAOD,QAAA,MAAM,KAAK,EAAE,OAAO,EAsBnB,CAAC;AAEF,iBAAS,IAAI,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAEhC;AAED,iBAAS,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAGjC;AAED;+CAC+C;AAC/C,iBAAe,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAqBlH;AAED,iBAAS,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,IAAI,CASxF;AAED,iBAAe,MAAM,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA6CpD;AAED,iBAAS,IAAI,IAAI,IAAI,CAmBpB"}
1
+ {"version":3,"file":"forge_panel_server.d.ts","sourceRoot":"","sources":["../../src/mcp/forge_panel_server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG"}
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * forge_panel_server.ts -- PND-064 slice B.
4
3
  *
@@ -18,6 +17,7 @@
18
17
  * Hand-rolled JSON-RPC 2.0 sobre stdio (estilo zero-dep del repo,
19
18
  * espejo del cliente en protocol_client.ts). ASCII-only.
20
19
  */
20
+ import { forwardInvoke } from './panel_invoke.js';
21
21
  /* PND-064 -- una sola tool `nac3_invoke` que proxea el catalogo
22
22
  * COMPLETO de verbos yujin (igual que el modo API). El subproceso
23
23
  * ya tiene el manifest de verbos en su system prompt; esta tool es
@@ -55,31 +55,10 @@ function logErr(msg) {
55
55
  }
56
56
  catch { /* ignore */ }
57
57
  }
58
- /** Reenvia un nac3_invoke al chat server (que corre el dispatcher
59
- * real) y devuelve el texto del resultado. */
60
- async function forwardInvoke(verbId, args) {
61
- const port = process.env['FORGE_PANEL_PORT'];
62
- const token = process.env['FORGE_PANEL_TOKEN'];
63
- if (!port || !token) {
64
- return { ok: false, text: 'El canal de Forge no esta configurado (sin puerto/token).' };
65
- }
66
- try {
67
- const r = await fetch('http://127.0.0.1:' + port + '/api/forge/panel-invoke', {
68
- method: 'POST',
69
- headers: { 'content-type': 'application/json' },
70
- body: JSON.stringify({ token, verb_id: verbId, args }),
71
- });
72
- if (!r.ok) {
73
- return { ok: false, text: 'Forge rechazo la invocacion (HTTP ' + r.status + ').' };
74
- }
75
- const j = await r.json();
76
- return { ok: j.ok !== false, text: j.text || 'Listo.' };
77
- }
78
- catch (err) {
79
- const m = err instanceof Error ? err.message : String(err);
80
- return { ok: false, text: 'No pude contactar a Forge: ' + m };
81
- }
82
- }
58
+ /* El reenvio al chat server vive en panel_invoke.ts (PND-235). Estaba
59
+ * duplicado aca y en forge_verbs_server, y las dos copias esperaban la
60
+ * respuesta con `fetch`, heredando el techo de cinco minutos de undici: el
61
+ * mismo defecto, dos veces, y arreglado una sola. */
83
62
  function toolResult(id, text, isError = false) {
84
63
  send({
85
64
  jsonrpc: '2.0',
@@ -1 +1 @@
1
- {"version":3,"file":"forge_panel_server.js","sourceRoot":"","sources":["../../src/mcp/forge_panel_server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"forge_panel_server.js","sourceRoot":"","sources":["../../src/mcp/forge_panel_server.ts"],"names":[],"mappings":"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"}