oficina-opencode 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +174 -24
- package/dist/core/atomic.d.ts +85 -0
- package/dist/core/atomic.d.ts.map +1 -0
- package/dist/core/atomic.js +186 -0
- package/dist/core/atomic.js.map +1 -0
- package/dist/core/bus.d.ts +76 -56
- package/dist/core/bus.d.ts.map +1 -1
- package/dist/core/bus.js +141 -100
- package/dist/core/bus.js.map +1 -1
- package/dist/core/catalog.d.ts +27 -0
- package/dist/core/catalog.d.ts.map +1 -1
- package/dist/core/catalog.js +41 -6
- package/dist/core/catalog.js.map +1 -1
- package/dist/core/cost.d.ts +275 -0
- package/dist/core/cost.d.ts.map +1 -0
- package/dist/core/cost.js +724 -0
- package/dist/core/cost.js.map +1 -0
- package/dist/core/docsync.d.ts +124 -0
- package/dist/core/docsync.d.ts.map +1 -0
- package/dist/core/docsync.js +191 -0
- package/dist/core/docsync.js.map +1 -0
- package/dist/core/evidence.d.ts +314 -0
- package/dist/core/evidence.d.ts.map +1 -0
- package/dist/core/evidence.js +602 -0
- package/dist/core/evidence.js.map +1 -0
- package/dist/core/fsx.d.ts.map +1 -1
- package/dist/core/fsx.js +7 -1
- package/dist/core/fsx.js.map +1 -1
- package/dist/core/gates.d.ts +9 -2
- package/dist/core/gates.d.ts.map +1 -1
- package/dist/core/gates.js +19 -3
- package/dist/core/gates.js.map +1 -1
- package/dist/core/ids.d.ts +48 -0
- package/dist/core/ids.d.ts.map +1 -0
- package/dist/core/ids.js +87 -0
- package/dist/core/ids.js.map +1 -0
- package/dist/core/leases.d.ts +45 -0
- package/dist/core/leases.d.ts.map +1 -1
- package/dist/core/leases.js +85 -17
- package/dist/core/leases.js.map +1 -1
- package/dist/core/office.d.ts +72 -1
- package/dist/core/office.d.ts.map +1 -1
- package/dist/core/office.js +173 -6
- package/dist/core/office.js.map +1 -1
- package/dist/core/paths.d.ts +11 -1
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +28 -4
- package/dist/core/paths.js.map +1 -1
- package/dist/core/recovery.d.ts +87 -0
- package/dist/core/recovery.d.ts.map +1 -0
- package/dist/core/recovery.js +325 -0
- package/dist/core/recovery.js.map +1 -0
- package/dist/core/sandbox.d.ts +179 -0
- package/dist/core/sandbox.d.ts.map +1 -0
- package/dist/core/sandbox.js +546 -0
- package/dist/core/sandbox.js.map +1 -0
- package/dist/core/state.d.ts +7 -0
- package/dist/core/state.d.ts.map +1 -1
- package/dist/core/state.js +15 -1
- package/dist/core/state.js.map +1 -1
- package/dist/core/stores.d.ts +65 -0
- package/dist/core/stores.d.ts.map +1 -0
- package/dist/core/stores.js +115 -0
- package/dist/core/stores.js.map +1 -0
- package/dist/core/tripwire.d.ts +87 -0
- package/dist/core/tripwire.d.ts.map +1 -0
- package/dist/core/tripwire.js +203 -0
- package/dist/core/tripwire.js.map +1 -0
- package/dist/core/types.d.ts +33 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +1 -0
- package/dist/core/types.js.map +1 -1
- package/dist/hooks/scopeGuard.d.ts +86 -13
- package/dist/hooks/scopeGuard.d.ts.map +1 -1
- package/dist/hooks/scopeGuard.js +296 -62
- package/dist/hooks/scopeGuard.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +185 -2
- package/dist/index.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +158 -0
- package/dist/tools/index.js.map +1 -1
- package/docs/COMPATIBILITY.md +98 -0
- package/docs/GARANTIAS.md +190 -0
- package/docs/PLAN-V2.1.md +144 -0
- package/docs/QUE-ES.md +15 -0
- package/docs/catalog-facts.json +27 -0
- package/package.json +10 -6
package/dist/core/types.js
CHANGED
package/dist/core/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAqDH,MAAM,CAAC,MAAM,cAAc,GAAW;IACpC,mBAAmB,EAAE,EAAE;IACvB,aAAa,EAAE,CAAC;IAChB,cAAc,EAAE,EAAE;IAClB,gBAAgB,EAAE,CAAC;IACnB,mBAAmB,EAAE,GAAG;IACxB,SAAS,EAAE,GAAG;IACd,WAAW,EAAE,IAAI;IACjB,YAAY,EAAE,EAAE;IAChB,mBAAmB,EAAE,CAAC;IACtB,QAAQ,EAAE,EAAE;IACZ,aAAa,EAAE,EAAE;IACjB,kBAAkB,EAAE,GAAG;IACvB,sBAAsB,EAAE,IAAI;IAC5B,0BAA0B,EAAE,IAAI;IAChC,gBAAgB,EAAE,IAAI;CACvB,CAAA"}
|
|
@@ -5,30 +5,102 @@
|
|
|
5
5
|
* una instrucción en una restricción. Un prompt le pide al modelo que sea
|
|
6
6
|
* cuidadoso; este hook le impide hacerlo.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* su card, la operación se rechaza con un error que explica qué hacer.
|
|
8
|
+
* ## Qué cambió y por qué
|
|
10
9
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* La versión anterior comparaba strings:
|
|
11
|
+
*
|
|
12
|
+
* const relative = path.relative(projectRoot, absolute)
|
|
13
|
+
* if (!matchesScope(relative, mayTouch)) throw ...
|
|
14
|
+
*
|
|
15
|
+
* Eso se puede eludir por tres vías, y las tres eran reales:
|
|
16
|
+
*
|
|
17
|
+
* 1. **Symlink.** `src/link.ts` -> `../../etc/secrets.ts`. El relativo es
|
|
18
|
+
* `src/link.ts`, que matchea `src/**`. Autorizado. La escritura pasa.
|
|
19
|
+
* 2. **`mayTouch: ["**"]`.** `**` matcheaba cualquier string, incluido
|
|
20
|
+
* `../../etc/passwd`. Un `**` tiene que significar "el proyecto", no
|
|
21
|
+
* "el filesystem".
|
|
22
|
+
* 3. **Paths absolutos.** `/etc/passwd` tiene un relativo `../../etc/passwd`
|
|
23
|
+
* y con `**` pasaba de largo.
|
|
24
|
+
*
|
|
25
|
+
* Ahora la ruta se **resuelve** (absoluta -> normalizada -> symlinks
|
|
26
|
+
* resueltos -> realpath) y recién ahí se decide. Y la decisión es
|
|
27
|
+
* fail-closed.
|
|
28
|
+
*
|
|
29
|
+
* ## Qué cubre ahora
|
|
30
|
+
*
|
|
31
|
+
* - **Todas las tools que escriben un archivo**, no solo `edit`/`write`:
|
|
32
|
+
* `patch` (incluyendo diffs multi-archivo), `multiedit`, `notebook_edit`,
|
|
33
|
+
* `str_replace`, y las variantes con prefijo de provider.
|
|
34
|
+
* - **Los comandos de shell.** `bash > ../fuera`, `cp a /etc/passwd`,
|
|
35
|
+
* `sed -i`, `python -c "open(...)"` se analizan antes de ejecutarse.
|
|
36
|
+
* - **Los subagentes.** Un subagente es una sesion hija; el guard sube por
|
|
37
|
+
* la cadena de padres hasta encontrar la sesion que tiene la card, y le
|
|
38
|
+
* aplica el MISMO scope. Sin esto, delegar era un escalón para salirse.
|
|
39
|
+
* - **Los archivos sensibles.** `.env`, `.npmrc`, `.git/**`, claves privadas:
|
|
40
|
+
* jamas escribibles, pase lo que pase el scope de la card.
|
|
41
|
+
*
|
|
42
|
+
* ## Lo que este hook NO puede hacer
|
|
43
|
+
*
|
|
44
|
+
* Un comando de shell con un interpreter embebido puede escribir en
|
|
45
|
+
* cualquier lado, y no hay forma de saberlo antes de correrlo. Para eso
|
|
46
|
+
* esta el tripwire (`core/tripwire.ts`): se arma antes del comando y se
|
|
47
|
+
* verifica despues. Es deteccion, no prevencion — y por eso el README lo
|
|
48
|
+
* dice asi, en vez de prometer un aislamiento que no existe.
|
|
14
49
|
*/
|
|
50
|
+
import type { Card, OfficeState } from "../core/types.js";
|
|
15
51
|
import type { Office } from "../core/office.js";
|
|
52
|
+
import { globToRegex, matchesScope } from "../core/sandbox.js";
|
|
16
53
|
export interface ScopeGuardOptions {
|
|
17
54
|
/** Si es false, el guard solo avisa y no bloquea. */
|
|
18
55
|
enforce: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Resuelve el `parentID` de una sesión.
|
|
58
|
+
*
|
|
59
|
+
* Es lo que hace que los subagentes hereden el scope: el hijo sube por
|
|
60
|
+
* la cadena hasta encontrar la sesión con la card.
|
|
61
|
+
*/
|
|
62
|
+
resolveParentSession?: (sessionID: string) => Promise<string | undefined>;
|
|
63
|
+
/**
|
|
64
|
+
* Qué hacer con los comandos de shell.
|
|
65
|
+
*
|
|
66
|
+
* - `block`: un comando que claramente escribe fuera del scope se bloquea.
|
|
67
|
+
* - `warn`: se avisa pero se deja pasar (el tripwire cubre).
|
|
68
|
+
*/
|
|
69
|
+
shellPolicy?: "block" | "warn";
|
|
70
|
+
/** Profundidad maxima de la cadena de padres que se recorre. */
|
|
71
|
+
maxParentDepth?: number;
|
|
19
72
|
}
|
|
20
73
|
/**
|
|
21
|
-
*
|
|
74
|
+
* Extrae TODOS los paths que una tool de escritura quiere tocar.
|
|
22
75
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
76
|
+
* La versión anterior devolvía un solo path, y para `patch` leía **solo el
|
|
77
|
+
* primer** `---` del diff. Un diff de cinco archivos pasaba el control con
|
|
78
|
+
* el primero y se escribían los otros cuatro.
|
|
79
|
+
*/
|
|
80
|
+
export declare function extractPaths(tool: string, args: Record<string, unknown>): string[];
|
|
81
|
+
/**
|
|
82
|
+
* Paths de un diff unificado.
|
|
83
|
+
*
|
|
84
|
+
* Lee **todas** las lineas `---` y `+++`. Si el diff usa el prefijo de git
|
|
85
|
+
* (`a/`, `b/`) se lo saca, pero solo si AMBOS lados lo usan: un archivo
|
|
86
|
+
* llamado `a/notas.md` es un path legitimo.
|
|
87
|
+
*/
|
|
88
|
+
export declare function pathsFromPatch(patch: string): string[];
|
|
89
|
+
/**
|
|
90
|
+
* El path de una tool de escritura. Se mantiene por compatibilidad con el
|
|
91
|
+
* API anterior; `extractPaths` es la version que hay que usar.
|
|
26
92
|
*/
|
|
27
|
-
export declare function globToRegex(glob: string): RegExp;
|
|
28
|
-
/** ¿El path cae dentro de alguno de los globs? */
|
|
29
|
-
export declare function matchesScope(relativePath: string, globs: string[]): boolean;
|
|
30
|
-
/** Extrae el path del argumento de una tool de escritura. */
|
|
31
93
|
export declare function extractPath(tool: string, args: Record<string, unknown>): string | undefined;
|
|
94
|
+
/** El comando de una tool de shell. */
|
|
95
|
+
export declare function extractCommand(args: Record<string, unknown>): string | undefined;
|
|
96
|
+
/**
|
|
97
|
+
* La card que gobierna una sesión.
|
|
98
|
+
*
|
|
99
|
+
* Primero mira el binding directo. Si no hay, sube por la cadena de
|
|
100
|
+
* padres: un subagente es una sesión hija, y su scope es el de quien lo
|
|
101
|
+
* lanzo.
|
|
102
|
+
*/
|
|
103
|
+
export declare function resolveScopeCard(state: OfficeState, sessionID: string, options: ScopeGuardOptions): Promise<Card | undefined>;
|
|
32
104
|
export declare function createScopeGuardHook(office: Office, options?: ScopeGuardOptions): (input: {
|
|
33
105
|
tool: string;
|
|
34
106
|
sessionID: string;
|
|
@@ -36,4 +108,5 @@ export declare function createScopeGuardHook(office: Office, options?: ScopeGuar
|
|
|
36
108
|
}, output: {
|
|
37
109
|
args: Record<string, unknown>;
|
|
38
110
|
}) => Promise<void>;
|
|
111
|
+
export { globToRegex, matchesScope };
|
|
39
112
|
//# sourceMappingURL=scopeGuard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scopeGuard.d.ts","sourceRoot":"","sources":["../../src/hooks/scopeGuard.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"scopeGuard.d.ts","sourceRoot":"","sources":["../../src/hooks/scopeGuard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAGL,WAAW,EACX,YAAY,EAEb,MAAM,oBAAoB,CAAA;AA8C3B,MAAM,WAAW,iBAAiB;IAChC,qDAAqD;IACrD,OAAO,EAAE,OAAO,CAAA;IAChB;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACzE;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IAC9B,gEAAgE;IAChE,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AASD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,CAiDlF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA2BtD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,SAAS,CAE3F;AAED,uCAAuC;AACvC,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,SAAS,CAMhF;AAMD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAkC3B;AAUD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAqC,IAI/F,OAAO;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAC1D,QAAQ;IAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,KACxC,OAAO,CAAC,IAAI,CAAC,CAoFjB;AAED,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,CAAA"}
|
package/dist/hooks/scopeGuard.js
CHANGED
|
@@ -5,100 +5,333 @@
|
|
|
5
5
|
* una instrucción en una restricción. Un prompt le pide al modelo que sea
|
|
6
6
|
* cuidadoso; este hook le impide hacerlo.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* su card, la operación se rechaza con un error que explica qué hacer.
|
|
8
|
+
* ## Qué cambió y por qué
|
|
10
9
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* La versión anterior comparaba strings:
|
|
11
|
+
*
|
|
12
|
+
* const relative = path.relative(projectRoot, absolute)
|
|
13
|
+
* if (!matchesScope(relative, mayTouch)) throw ...
|
|
14
|
+
*
|
|
15
|
+
* Eso se puede eludir por tres vías, y las tres eran reales:
|
|
16
|
+
*
|
|
17
|
+
* 1. **Symlink.** `src/link.ts` -> `../../etc/secrets.ts`. El relativo es
|
|
18
|
+
* `src/link.ts`, que matchea `src/**`. Autorizado. La escritura pasa.
|
|
19
|
+
* 2. **`mayTouch: ["**"]`.** `**` matcheaba cualquier string, incluido
|
|
20
|
+
* `../../etc/passwd`. Un `**` tiene que significar "el proyecto", no
|
|
21
|
+
* "el filesystem".
|
|
22
|
+
* 3. **Paths absolutos.** `/etc/passwd` tiene un relativo `../../etc/passwd`
|
|
23
|
+
* y con `**` pasaba de largo.
|
|
24
|
+
*
|
|
25
|
+
* Ahora la ruta se **resuelve** (absoluta -> normalizada -> symlinks
|
|
26
|
+
* resueltos -> realpath) y recién ahí se decide. Y la decisión es
|
|
27
|
+
* fail-closed.
|
|
28
|
+
*
|
|
29
|
+
* ## Qué cubre ahora
|
|
30
|
+
*
|
|
31
|
+
* - **Todas las tools que escriben un archivo**, no solo `edit`/`write`:
|
|
32
|
+
* `patch` (incluyendo diffs multi-archivo), `multiedit`, `notebook_edit`,
|
|
33
|
+
* `str_replace`, y las variantes con prefijo de provider.
|
|
34
|
+
* - **Los comandos de shell.** `bash > ../fuera`, `cp a /etc/passwd`,
|
|
35
|
+
* `sed -i`, `python -c "open(...)"` se analizan antes de ejecutarse.
|
|
36
|
+
* - **Los subagentes.** Un subagente es una sesion hija; el guard sube por
|
|
37
|
+
* la cadena de padres hasta encontrar la sesion que tiene la card, y le
|
|
38
|
+
* aplica el MISMO scope. Sin esto, delegar era un escalón para salirse.
|
|
39
|
+
* - **Los archivos sensibles.** `.env`, `.npmrc`, `.git/**`, claves privadas:
|
|
40
|
+
* jamas escribibles, pase lo que pase el scope de la card.
|
|
41
|
+
*
|
|
42
|
+
* ## Lo que este hook NO puede hacer
|
|
43
|
+
*
|
|
44
|
+
* Un comando de shell con un interpreter embebido puede escribir en
|
|
45
|
+
* cualquier lado, y no hay forma de saberlo antes de correrlo. Para eso
|
|
46
|
+
* esta el tripwire (`core/tripwire.ts`): se arma antes del comando y se
|
|
47
|
+
* verifica despues. Es deteccion, no prevencion — y por eso el README lo
|
|
48
|
+
* dice asi, en vez de prometer un aislamiento que no existe.
|
|
14
49
|
*/
|
|
15
|
-
import
|
|
50
|
+
import { analyzeShellCommand, checkScope, globToRegex, matchesScope, } from "../core/sandbox.js";
|
|
16
51
|
import { logger } from "../core/log.js";
|
|
17
52
|
const log = logger("oficina:scope-guard");
|
|
18
|
-
/** Tools que escriben en disco. */
|
|
19
|
-
const WRITE_TOOLS = new Set(["edit", "write", "patch", "multiedit", "apply_patch"]);
|
|
20
53
|
/**
|
|
21
|
-
*
|
|
54
|
+
* Tools que escriben UN archivo.
|
|
22
55
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
56
|
+
* Se listan con prefijos porque cada provider registra sus tools con
|
|
57
|
+
* nombre distinto (`str_replace`, `str_replace_based_edit_tool`,
|
|
58
|
+
* `edit_notebook_file`...). El prefijo cubre la familia entera.
|
|
26
59
|
*/
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
60
|
+
const FILE_WRITE_TOOLS = new Set([
|
|
61
|
+
"edit",
|
|
62
|
+
"write",
|
|
63
|
+
"patch",
|
|
64
|
+
"multiedit",
|
|
65
|
+
"apply_patch",
|
|
66
|
+
"notebook_edit",
|
|
67
|
+
"str_replace",
|
|
68
|
+
"str_replace_editor",
|
|
69
|
+
"str_replace_based_edit_tool",
|
|
70
|
+
"edit_file",
|
|
71
|
+
"edit_notebook_file",
|
|
72
|
+
"create_file",
|
|
73
|
+
"write_file",
|
|
74
|
+
"create_or_update_file",
|
|
75
|
+
"multi_edit",
|
|
76
|
+
]);
|
|
77
|
+
/** Tools que ejecutan shell. */
|
|
78
|
+
const SHELL_TOOLS = new Set([
|
|
79
|
+
"bash",
|
|
80
|
+
"shell",
|
|
81
|
+
"run",
|
|
82
|
+
"run_command",
|
|
83
|
+
"execute_command",
|
|
84
|
+
"terminal",
|
|
85
|
+
"powershell",
|
|
86
|
+
"cmd",
|
|
87
|
+
"powershell.exe",
|
|
88
|
+
]);
|
|
89
|
+
/** Tools que delegan a otro agente. */
|
|
90
|
+
const DELEGATE_TOOLS = new Set(["task", "agent", "subagent", "spawn_agent"]);
|
|
91
|
+
/* ────────────────────────────────────────────────────────────────────────────
|
|
92
|
+
* Extraccion de paths
|
|
93
|
+
* ──────────────────────────────────────────────────────────────────────────── */
|
|
94
|
+
/** Claves de argumento que contienen un path de archivo. */
|
|
95
|
+
const PATH_KEYS = ["filePath", "path", "file", "target", "notebook_path", "filename", "file_path"];
|
|
96
|
+
/**
|
|
97
|
+
* Extrae TODOS los paths que una tool de escritura quiere tocar.
|
|
98
|
+
*
|
|
99
|
+
* La versión anterior devolvía un solo path, y para `patch` leía **solo el
|
|
100
|
+
* primer** `---` del diff. Un diff de cinco archivos pasaba el control con
|
|
101
|
+
* el primero y se escribían los otros cuatro.
|
|
102
|
+
*/
|
|
103
|
+
export function extractPaths(tool, args) {
|
|
104
|
+
const out = [];
|
|
105
|
+
for (const key of PATH_KEYS) {
|
|
106
|
+
const value = args[key];
|
|
107
|
+
if (typeof value === "string" && value.length > 0)
|
|
108
|
+
out.push(value);
|
|
109
|
+
else if (Array.isArray(value)) {
|
|
110
|
+
for (const v of value)
|
|
111
|
+
if (typeof v === "string" && v.length > 0)
|
|
112
|
+
out.push(v);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// El tool `patch` puede traer los paths dentro de un patch estructurado.
|
|
116
|
+
const patch = args.patch ?? args.diff ?? args.edits;
|
|
117
|
+
if (typeof patch === "string") {
|
|
118
|
+
out.push(...pathsFromPatch(patch));
|
|
119
|
+
}
|
|
120
|
+
else if (Array.isArray(patch)) {
|
|
121
|
+
for (const entry of patch) {
|
|
122
|
+
if (typeof entry === "string")
|
|
123
|
+
out.push(...pathsFromPatch(entry));
|
|
124
|
+
else if (entry && typeof entry === "object") {
|
|
125
|
+
const rec = entry;
|
|
126
|
+
for (const key of PATH_KEYS) {
|
|
127
|
+
const v = rec[key];
|
|
128
|
+
if (typeof v === "string" && v.length > 0)
|
|
129
|
+
out.push(v);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Estructura `{ path, edits }` que usan algunos providers.
|
|
135
|
+
const edits = args.edits;
|
|
136
|
+
if (Array.isArray(edits)) {
|
|
137
|
+
for (const e of edits) {
|
|
138
|
+
if (e && typeof e === "object") {
|
|
139
|
+
const rec = e;
|
|
140
|
+
for (const key of PATH_KEYS) {
|
|
141
|
+
const v = rec[key];
|
|
142
|
+
if (typeof v === "string" && v.length > 0)
|
|
143
|
+
out.push(v);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Deduplicar conservando el orden.
|
|
149
|
+
const seen = new Set();
|
|
150
|
+
return out.filter((p) => {
|
|
151
|
+
if (seen.has(p))
|
|
152
|
+
return false;
|
|
153
|
+
seen.add(p);
|
|
154
|
+
return true;
|
|
46
155
|
});
|
|
47
156
|
}
|
|
48
|
-
/**
|
|
157
|
+
/**
|
|
158
|
+
* Paths de un diff unificado.
|
|
159
|
+
*
|
|
160
|
+
* Lee **todas** las lineas `---` y `+++`. Si el diff usa el prefijo de git
|
|
161
|
+
* (`a/`, `b/`) se lo saca, pero solo si AMBOS lados lo usan: un archivo
|
|
162
|
+
* llamado `a/notas.md` es un path legitimo.
|
|
163
|
+
*/
|
|
164
|
+
export function pathsFromPatch(patch) {
|
|
165
|
+
const minus = [];
|
|
166
|
+
const plus = [];
|
|
167
|
+
for (const line of patch.split(/\r?\n/)) {
|
|
168
|
+
const m = /^---+\s+(.+?)\s*$/.exec(line);
|
|
169
|
+
if (m?.[1])
|
|
170
|
+
minus.push(m[1]);
|
|
171
|
+
const p = /^\+\+\+\s+(.+?)\s*$/.exec(line);
|
|
172
|
+
if (p?.[1])
|
|
173
|
+
plus.push(p[1]);
|
|
174
|
+
}
|
|
175
|
+
const usaPrefijoGit = minus.length > 0 &&
|
|
176
|
+
minus.every((p) => p.startsWith("a/")) &&
|
|
177
|
+
plus.length > 0 &&
|
|
178
|
+
plus.every((p) => p.startsWith("b/"));
|
|
179
|
+
const strip = (p) => (usaPrefijoGit ? p.slice(2) : p);
|
|
180
|
+
// `--- /dev/null` marca un archivo nuevo: el path real viene del `+++`.
|
|
181
|
+
const out = [];
|
|
182
|
+
for (const p of [...minus, ...plus]) {
|
|
183
|
+
if (p === "/dev/null" || p === "dev/null")
|
|
184
|
+
continue;
|
|
185
|
+
const clean = strip(p);
|
|
186
|
+
if (clean)
|
|
187
|
+
out.push(clean);
|
|
188
|
+
}
|
|
189
|
+
return out;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* El path de una tool de escritura. Se mantiene por compatibilidad con el
|
|
193
|
+
* API anterior; `extractPaths` es la version que hay que usar.
|
|
194
|
+
*/
|
|
49
195
|
export function extractPath(tool, args) {
|
|
50
|
-
|
|
51
|
-
|
|
196
|
+
return extractPaths(tool, args)[0];
|
|
197
|
+
}
|
|
198
|
+
/** El comando de una tool de shell. */
|
|
199
|
+
export function extractCommand(args) {
|
|
200
|
+
for (const key of ["command", "cmd", "script", "input", "shellCommand"]) {
|
|
52
201
|
const value = args[key];
|
|
53
202
|
if (typeof value === "string" && value.length > 0)
|
|
54
203
|
return value;
|
|
55
204
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
/* ────────────────────────────────────────────────────────────────────────────
|
|
208
|
+
* Resolucion de scope
|
|
209
|
+
* ──────────────────────────────────────────────────────────────────────────── */
|
|
210
|
+
/**
|
|
211
|
+
* La card que gobierna una sesión.
|
|
212
|
+
*
|
|
213
|
+
* Primero mira el binding directo. Si no hay, sube por la cadena de
|
|
214
|
+
* padres: un subagente es una sesión hija, y su scope es el de quien lo
|
|
215
|
+
* lanzo.
|
|
216
|
+
*/
|
|
217
|
+
export async function resolveScopeCard(state, sessionID, options) {
|
|
218
|
+
const direct = state.sessions[sessionID];
|
|
219
|
+
if (direct?.cardId) {
|
|
220
|
+
const card = state.cards[direct.cardId];
|
|
221
|
+
if (card)
|
|
222
|
+
return card;
|
|
223
|
+
}
|
|
224
|
+
const resolveParent = options.resolveParentSession;
|
|
225
|
+
if (!resolveParent)
|
|
226
|
+
return undefined;
|
|
227
|
+
const maxDepth = options.maxParentDepth ?? 6;
|
|
228
|
+
const visited = new Set([sessionID]);
|
|
229
|
+
let current = sessionID;
|
|
230
|
+
for (let depth = 0; depth < maxDepth; depth += 1) {
|
|
231
|
+
let parent;
|
|
232
|
+
try {
|
|
233
|
+
parent = await resolveParent(current);
|
|
63
234
|
}
|
|
235
|
+
catch (err) {
|
|
236
|
+
log.debug("no se pudo resolver el padre de la sesion", { sessionID: current, error: String(err) });
|
|
237
|
+
return undefined;
|
|
238
|
+
}
|
|
239
|
+
if (!parent || visited.has(parent))
|
|
240
|
+
break;
|
|
241
|
+
visited.add(parent);
|
|
242
|
+
const binding = state.sessions[parent];
|
|
243
|
+
if (binding?.cardId) {
|
|
244
|
+
const card = state.cards[binding.cardId];
|
|
245
|
+
if (card)
|
|
246
|
+
return card;
|
|
247
|
+
}
|
|
248
|
+
current = parent;
|
|
64
249
|
}
|
|
65
250
|
return undefined;
|
|
66
251
|
}
|
|
252
|
+
/* ────────────────────────────────────────────────────────────────────────────
|
|
253
|
+
* Hook
|
|
254
|
+
* ──────────────────────────────────────────────────────────────────────────── */
|
|
255
|
+
function scopeError(verdict, card) {
|
|
256
|
+
return new Error(`[OFICINA] Scope violado: ${verdict.reason} (card ${card.id})`);
|
|
257
|
+
}
|
|
67
258
|
export function createScopeGuardHook(office, options = { enforce: true }) {
|
|
259
|
+
const shellPolicy = options.shellPolicy ?? "block";
|
|
68
260
|
return async function onToolExecuteBefore(input, output) {
|
|
69
|
-
|
|
261
|
+
const args = output?.args;
|
|
262
|
+
if (!args || typeof args !== "object")
|
|
70
263
|
return;
|
|
71
|
-
|
|
264
|
+
const tool = String(input.tool ?? "");
|
|
265
|
+
const isFileWrite = FILE_WRITE_TOOLS.has(tool);
|
|
266
|
+
const isShell = SHELL_TOOLS.has(tool);
|
|
267
|
+
const isDelegate = DELEGATE_TOOLS.has(tool);
|
|
268
|
+
if (!isFileWrite && !isShell && !isDelegate)
|
|
72
269
|
return;
|
|
73
270
|
try {
|
|
74
271
|
const state = await office.loadState();
|
|
75
|
-
const card =
|
|
272
|
+
const card = await resolveScopeCard(state, input.sessionID, options);
|
|
76
273
|
// Sin card activa no hay scope que aplicar: el agente está en
|
|
77
274
|
// exploración libre o en una operación que no es de la oficina.
|
|
78
275
|
if (!card)
|
|
79
276
|
return;
|
|
80
|
-
const
|
|
81
|
-
|
|
277
|
+
const policy = { mayTouch: card.scope.mayTouch, forbidden: card.scope.forbidden };
|
|
278
|
+
const projectRoot = office.paths.projectRoot;
|
|
279
|
+
/* ── Archivos ────────────────────────────────────────────────────── */
|
|
280
|
+
if (isFileWrite) {
|
|
281
|
+
const paths = extractPaths(tool, args);
|
|
282
|
+
if (paths.length === 0)
|
|
283
|
+
return;
|
|
284
|
+
for (const p of paths) {
|
|
285
|
+
const verdict = await checkScope(projectRoot, p, policy);
|
|
286
|
+
if (!verdict.allowed) {
|
|
287
|
+
log.warn("scope violado (archivo)", { card: card.id, path: p, kind: verdict.kind });
|
|
288
|
+
if (options.enforce)
|
|
289
|
+
throw scopeError(verdict, card);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
log.debug("scope ok", { card: card.id, tool, paths: paths.length });
|
|
82
293
|
return;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
294
|
+
}
|
|
295
|
+
/* ── Shell ───────────────────────────────────────────────────────── */
|
|
296
|
+
if (isShell) {
|
|
297
|
+
const command = extractCommand(args);
|
|
298
|
+
if (!command)
|
|
299
|
+
return;
|
|
300
|
+
const candidates = analyzeShellCommand(command);
|
|
301
|
+
if (candidates.length === 0)
|
|
302
|
+
return;
|
|
303
|
+
for (const candidate of candidates) {
|
|
304
|
+
if (candidate.uncertain) {
|
|
305
|
+
// Hay una escritura que no sabemos interpretar. No se bloquea
|
|
306
|
+
// (seria inservible) pero se avisa: el tripwire va a vigilar.
|
|
307
|
+
log.warn("shell con escritura no interpretable", {
|
|
308
|
+
card: card.id,
|
|
309
|
+
op: candidate.op,
|
|
310
|
+
command: command.slice(0, 200),
|
|
311
|
+
});
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
const verdict = await checkScope(projectRoot, candidate.target, policy);
|
|
315
|
+
if (!verdict.allowed) {
|
|
316
|
+
log.warn("scope violado (shell)", {
|
|
317
|
+
card: card.id,
|
|
318
|
+
target: candidate.target,
|
|
319
|
+
op: candidate.op,
|
|
320
|
+
kind: verdict.kind,
|
|
321
|
+
});
|
|
322
|
+
if (options.enforce && shellPolicy === "block") {
|
|
323
|
+
throw scopeError(verdict, card);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
89
327
|
return;
|
|
90
|
-
const mayTouch = card.scope.mayTouch;
|
|
91
|
-
const forbidden = card.scope.forbidden;
|
|
92
|
-
if (matchesScope(relative, forbidden)) {
|
|
93
|
-
throw new Error(`[OFICINA] Scope violado: \`${relative}\` está en el scope forbidden de la card ${card.id}. ` +
|
|
94
|
-
`Forbidden: ${forbidden.join(", ")}. No lo toques. Si realmente hace falta, pedí que se amplíe el scope.`);
|
|
95
328
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
329
|
+
/* ── Delegacion ──────────────────────────────────────────────────── */
|
|
330
|
+
// Delegar no escribe, pero crea un actor nuevo. Se registra para que
|
|
331
|
+
// el subagente herede el scope cuando el motor cree su sesion.
|
|
332
|
+
if (isDelegate) {
|
|
333
|
+
log.debug("delegacion dentro de scope", { card: card.id, tool });
|
|
100
334
|
}
|
|
101
|
-
log.debug("scope ok", { card: card.id, file: relative });
|
|
102
335
|
}
|
|
103
336
|
catch (err) {
|
|
104
337
|
if (err instanceof Error && err.message.startsWith("[OFICINA]")) {
|
|
@@ -111,4 +344,5 @@ export function createScopeGuardHook(office, options = { enforce: true }) {
|
|
|
111
344
|
}
|
|
112
345
|
};
|
|
113
346
|
}
|
|
347
|
+
export { globToRegex, matchesScope };
|
|
114
348
|
//# sourceMappingURL=scopeGuard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scopeGuard.js","sourceRoot":"","sources":["../../src/hooks/scopeGuard.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"scopeGuard.js","sourceRoot":"","sources":["../../src/hooks/scopeGuard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAIH,OAAO,EACL,mBAAmB,EACnB,UAAU,EACV,WAAW,EACX,YAAY,GAEb,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAEvC,MAAM,GAAG,GAAG,MAAM,CAAC,qBAAqB,CAAC,CAAA;AAEzC;;;;;;GAMG;AACH,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAC/B,MAAM;IACN,OAAO;IACP,OAAO;IACP,WAAW;IACX,aAAa;IACb,eAAe;IACf,aAAa;IACb,oBAAoB;IACpB,6BAA6B;IAC7B,WAAW;IACX,oBAAoB;IACpB,aAAa;IACb,YAAY;IACZ,uBAAuB;IACvB,YAAY;CACb,CAAC,CAAA;AAEF,gCAAgC;AAChC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;IAC1B,MAAM;IACN,OAAO;IACP,KAAK;IACL,aAAa;IACb,iBAAiB;IACjB,UAAU;IACV,YAAY;IACZ,KAAK;IACL,gBAAgB;CACjB,CAAC,CAAA;AAEF,uCAAuC;AACvC,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC,CAAA;AAuB5E;;kFAEkF;AAElF,4DAA4D;AAC5D,MAAM,SAAS,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,CAAC,CAAA;AAElG;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,IAA6B;IACtE,MAAM,GAAG,GAAa,EAAE,CAAA;IAExB,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAA;QACvB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;aAC7D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,KAAK,MAAM,CAAC,IAAI,KAAK;gBAAE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;oBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAC/E,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAA;IACnD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,GAAG,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;IACpC,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;YAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;iBAC5D,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC5C,MAAM,GAAG,GAAG,KAAgC,CAAA;gBAC5C,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;oBAC5B,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAA;oBAClB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;wBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;gBACxD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,2DAA2D;IAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;IACxB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;gBAC/B,MAAM,GAAG,GAAG,CAA4B,CAAA;gBACxC,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;oBAC5B,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAA;oBAClB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;wBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;gBACxD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,mCAAmC;IACnC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACtB,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAA;QAC7B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;QACX,OAAO,IAAI,CAAA;IACb,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,MAAM,IAAI,GAAa,EAAE,CAAA;IAEzB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACxC,MAAM,CAAC,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACxC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAC5B,MAAM,CAAC,GAAG,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC1C,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAC7B,CAAC;IAED,MAAM,aAAa,GACjB,KAAK,CAAC,MAAM,GAAG,CAAC;QAChB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,GAAG,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;IAEvC,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAE7D,wEAAwE;IACxE,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;QACpC,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,UAAU;YAAE,SAAQ;QACnD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QACtB,IAAI,KAAK;YAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC5B,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,IAA6B;IACrE,OAAO,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;AACpC,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,cAAc,CAAC,IAA6B;IAC1D,KAAK,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,CAAC,EAAE,CAAC;QACxE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAA;QACvB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,KAAK,CAAA;IACjE,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;kFAEkF;AAElF;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAkB,EAClB,SAAiB,EACjB,OAA0B;IAE1B,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;IACxC,IAAI,MAAM,EAAE,MAAM,EAAE,CAAC;QACnB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QACvC,IAAI,IAAI;YAAE,OAAO,IAAI,CAAA;IACvB,CAAC;IAED,MAAM,aAAa,GAAG,OAAO,CAAC,oBAAoB,CAAA;IAClD,IAAI,CAAC,aAAa;QAAE,OAAO,SAAS,CAAA;IAEpC,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,IAAI,CAAC,CAAA;IAC5C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAS,CAAC,SAAS,CAAC,CAAC,CAAA;IAC5C,IAAI,OAAO,GAAG,SAAS,CAAA;IAEvB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,QAAQ,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACjD,IAAI,MAA0B,CAAA;QAC9B,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,CAAA;QACvC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,2CAA2C,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YAClG,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,MAAK;QACzC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QAEnB,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;QACtC,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;YACpB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;YACxC,IAAI,IAAI;gBAAE,OAAO,IAAI,CAAA;QACvB,CAAC;QACD,OAAO,GAAG,MAAM,CAAA;IAClB,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;kFAEkF;AAElF,SAAS,UAAU,CAAC,OAAqB,EAAE,IAAU;IACnD,OAAO,IAAI,KAAK,CAAC,4BAA4B,OAAO,CAAC,MAAM,UAAU,IAAI,CAAC,EAAE,GAAG,CAAC,CAAA;AAClF,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAc,EAAE,UAA6B,EAAE,OAAO,EAAE,IAAI,EAAE;IACjG,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAA;IAElD,OAAO,KAAK,UAAU,mBAAmB,CACvC,KAA0D,EAC1D,MAAyC;QAEzC,MAAM,IAAI,GAAG,MAAM,EAAE,IAAI,CAAA;QACzB,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,OAAM;QAE7C,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;QACrC,MAAM,WAAW,GAAG,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACrC,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAC3C,IAAI,CAAC,WAAW,IAAI,CAAC,OAAO,IAAI,CAAC,UAAU;YAAE,OAAM;QAEnD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,CAAA;YACtC,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;YACpE,8DAA8D;YAC9D,gEAAgE;YAChE,IAAI,CAAC,IAAI;gBAAE,OAAM;YAEjB,MAAM,MAAM,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAA;YACjF,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,WAAW,CAAA;YAE5C,wEAAwE;YACxE,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;gBACtC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;oBAAE,OAAM;gBAC9B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;oBACtB,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,WAAW,EAAE,CAAC,EAAE,MAAM,CAAC,CAAA;oBACxD,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;wBACrB,GAAG,CAAC,IAAI,CAAC,yBAAyB,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;wBACnF,IAAI,OAAO,CAAC,OAAO;4BAAE,MAAM,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;oBACtD,CAAC;gBACH,CAAC;gBACD,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAA;gBACnE,OAAM;YACR,CAAC;YAED,wEAAwE;YACxE,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,CAAA;gBACpC,IAAI,CAAC,OAAO;oBAAE,OAAM;gBACpB,MAAM,UAAU,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAA;gBAC/C,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;oBAAE,OAAM;gBAEnC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;oBACnC,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;wBACxB,8DAA8D;wBAC9D,8DAA8D;wBAC9D,GAAG,CAAC,IAAI,CAAC,sCAAsC,EAAE;4BAC/C,IAAI,EAAE,IAAI,CAAC,EAAE;4BACb,EAAE,EAAE,SAAS,CAAC,EAAE;4BAChB,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;yBAC/B,CAAC,CAAA;wBACF,SAAQ;oBACV,CAAC;oBACD,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,WAAW,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;oBACvE,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;wBACrB,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE;4BAChC,IAAI,EAAE,IAAI,CAAC,EAAE;4BACb,MAAM,EAAE,SAAS,CAAC,MAAM;4BACxB,EAAE,EAAE,SAAS,CAAC,EAAE;4BAChB,IAAI,EAAE,OAAO,CAAC,IAAI;yBACnB,CAAC,CAAA;wBACF,IAAI,OAAO,CAAC,OAAO,IAAI,WAAW,KAAK,OAAO,EAAE,CAAC;4BAC/C,MAAM,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;wBACjC,CAAC;oBACH,CAAC;gBACH,CAAC;gBACD,OAAM;YACR,CAAC;YAED,wEAAwE;YACxE,qEAAqE;YACrE,+DAA+D;YAC/D,IAAI,UAAU,EAAE,CAAC;gBACf,GAAG,CAAC,KAAK,CAAC,4BAA4B,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;YAClE,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;gBAChE,IAAI,OAAO,CAAC,OAAO;oBAAE,MAAM,GAAG,CAAA;gBAC9B,GAAG,CAAC,IAAI,CAAC,8BAA8B,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;gBAChE,OAAM;YACR,CAAC;YACD,GAAG,CAAC,KAAK,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACjE,CAAC;IACH,CAAC,CAAA;AACH,CAAC;AAED,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,10 +8,18 @@
|
|
|
8
8
|
* incansablemente" sea una propiedad del sistema y no un pedido.
|
|
9
9
|
* - **Hook `tool.execute.before`**: guard de scope. "No toques fuera de tu
|
|
10
10
|
* scope" pasa de ser una instrucción a ser una restricción.
|
|
11
|
+
* - **Hook `tool.execute.after`**: tripwire. Detecta lo que el guard no
|
|
12
|
+
* pudo ver: escrituras que se colaron por un comando de shell.
|
|
13
|
+
* - **Hook `permission.ask`**: segunda capa de enforcement, a nivel del
|
|
14
|
+
* framework. Cuando OpenCode pide permiso para una escritura, la oficina
|
|
15
|
+
* lo deniega si está fuera del scope.
|
|
16
|
+
* - **Hook `event` → message.updated**: contabilidad de costo. El motor ya
|
|
17
|
+
* sabe cuánto costó cada llamada; la oficina lo anota y lo presupuesta.
|
|
11
18
|
* - **Hook `experimental.chat.system.transform`**: el estado de la oficina
|
|
12
19
|
* viaja con cada llamada. El agente no repregunta lo que ya sabe.
|
|
13
20
|
* - **Hook `experimental.session.compacting`**: el estado sobrevive a la
|
|
14
21
|
* compactación.
|
|
22
|
+
* - **Hook `experimental.compaction.autocontinue`**: el freno de emergencia.
|
|
15
23
|
*
|
|
16
24
|
* Lo que NO hace: decidir el plan, escribir código ni emitir el veredicto de
|
|
17
25
|
* review. Eso sigue siendo del modelo. El código pone los límites; el modelo
|
|
@@ -27,6 +35,8 @@ export interface OficinaOptions {
|
|
|
27
35
|
maxAutoResumes?: number;
|
|
28
36
|
/** Si es false, el guard de scope avisa pero no bloquea. */
|
|
29
37
|
enforceScope?: boolean;
|
|
38
|
+
/** Tope de archivos que mira el tripwire por comando. */
|
|
39
|
+
tripwireMaxFiles?: number;
|
|
30
40
|
}
|
|
31
41
|
export declare const OficinaPlugin: Plugin;
|
|
32
42
|
export default OficinaPlugin;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAA;AAa9D,MAAM,WAAW,cAAc;IAC7B,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,6CAA6C;IAC7C,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,eAAO,MAAM,aAAa,EAAE,MAqR3B,CAAA;AAED,eAAe,aAAa,CAAA;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAA;AACnC,cAAc,iBAAiB,CAAA"}
|