oficina-opencode 2.0.1 → 2.1.1

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 (92) hide show
  1. package/README.md +164 -14
  2. package/commands/oficina.md +22 -9
  3. package/dist/core/atomic.d.ts +85 -0
  4. package/dist/core/atomic.d.ts.map +1 -0
  5. package/dist/core/atomic.js +186 -0
  6. package/dist/core/atomic.js.map +1 -0
  7. package/dist/core/bus.d.ts +76 -56
  8. package/dist/core/bus.d.ts.map +1 -1
  9. package/dist/core/bus.js +141 -100
  10. package/dist/core/bus.js.map +1 -1
  11. package/dist/core/catalog.d.ts +27 -0
  12. package/dist/core/catalog.d.ts.map +1 -1
  13. package/dist/core/catalog.js +41 -6
  14. package/dist/core/catalog.js.map +1 -1
  15. package/dist/core/cost.d.ts +275 -0
  16. package/dist/core/cost.d.ts.map +1 -0
  17. package/dist/core/cost.js +724 -0
  18. package/dist/core/cost.js.map +1 -0
  19. package/dist/core/docsync.d.ts +124 -0
  20. package/dist/core/docsync.d.ts.map +1 -0
  21. package/dist/core/docsync.js +191 -0
  22. package/dist/core/docsync.js.map +1 -0
  23. package/dist/core/evidence.d.ts +314 -0
  24. package/dist/core/evidence.d.ts.map +1 -0
  25. package/dist/core/evidence.js +602 -0
  26. package/dist/core/evidence.js.map +1 -0
  27. package/dist/core/fsx.d.ts.map +1 -1
  28. package/dist/core/fsx.js +7 -1
  29. package/dist/core/fsx.js.map +1 -1
  30. package/dist/core/gates.d.ts +9 -2
  31. package/dist/core/gates.d.ts.map +1 -1
  32. package/dist/core/gates.js +19 -3
  33. package/dist/core/gates.js.map +1 -1
  34. package/dist/core/ids.d.ts +48 -0
  35. package/dist/core/ids.d.ts.map +1 -0
  36. package/dist/core/ids.js +87 -0
  37. package/dist/core/ids.js.map +1 -0
  38. package/dist/core/leases.d.ts +45 -0
  39. package/dist/core/leases.d.ts.map +1 -1
  40. package/dist/core/leases.js +85 -17
  41. package/dist/core/leases.js.map +1 -1
  42. package/dist/core/office.d.ts +72 -1
  43. package/dist/core/office.d.ts.map +1 -1
  44. package/dist/core/office.js +173 -6
  45. package/dist/core/office.js.map +1 -1
  46. package/dist/core/paths.d.ts +11 -1
  47. package/dist/core/paths.d.ts.map +1 -1
  48. package/dist/core/paths.js +28 -4
  49. package/dist/core/paths.js.map +1 -1
  50. package/dist/core/recovery.d.ts +87 -0
  51. package/dist/core/recovery.d.ts.map +1 -0
  52. package/dist/core/recovery.js +325 -0
  53. package/dist/core/recovery.js.map +1 -0
  54. package/dist/core/sandbox.d.ts +179 -0
  55. package/dist/core/sandbox.d.ts.map +1 -0
  56. package/dist/core/sandbox.js +546 -0
  57. package/dist/core/sandbox.js.map +1 -0
  58. package/dist/core/state.d.ts +7 -0
  59. package/dist/core/state.d.ts.map +1 -1
  60. package/dist/core/state.js +15 -1
  61. package/dist/core/state.js.map +1 -1
  62. package/dist/core/stores.d.ts +65 -0
  63. package/dist/core/stores.d.ts.map +1 -0
  64. package/dist/core/stores.js +115 -0
  65. package/dist/core/stores.js.map +1 -0
  66. package/dist/core/tripwire.d.ts +87 -0
  67. package/dist/core/tripwire.d.ts.map +1 -0
  68. package/dist/core/tripwire.js +203 -0
  69. package/dist/core/tripwire.js.map +1 -0
  70. package/dist/core/types.d.ts +33 -1
  71. package/dist/core/types.d.ts.map +1 -1
  72. package/dist/core/types.js +1 -0
  73. package/dist/core/types.js.map +1 -1
  74. package/dist/hooks/scopeGuard.d.ts +86 -13
  75. package/dist/hooks/scopeGuard.d.ts.map +1 -1
  76. package/dist/hooks/scopeGuard.js +296 -62
  77. package/dist/hooks/scopeGuard.js.map +1 -1
  78. package/dist/index.d.ts +10 -0
  79. package/dist/index.d.ts.map +1 -1
  80. package/dist/index.js +185 -2
  81. package/dist/index.js.map +1 -1
  82. package/dist/tools/index.d.ts.map +1 -1
  83. package/dist/tools/index.js +158 -0
  84. package/dist/tools/index.js.map +1 -1
  85. package/docs/COMPATIBILITY.md +98 -0
  86. package/docs/GARANTIAS.md +190 -0
  87. package/docs/PLAN-V2.1.md +144 -0
  88. package/docs/QUE-ES.md +15 -0
  89. package/docs/catalog-facts.json +27 -0
  90. package/package.json +6 -2
  91. package/skills/oficina/SKILL.md +191 -69
  92. package/skills/oficina/reference/mesh.md +11 -2
@@ -22,6 +22,7 @@ export const DEFAULT_LIMITS = {
22
22
  maxAgentCalls: 40,
23
23
  minCatalogCoverage: 0.6,
24
24
  gateRequiredBeforeDone: true,
25
+ evidenceRequiredBeforeDone: true,
25
26
  reviewerNeqOwner: true,
26
27
  };
27
28
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA6CH,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,gBAAgB,EAAE,IAAI;CACvB,CAAA"}
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
- * Cuando una sesión intenta escribir un archivo que no está en el scope de
9
- * su card, la operación se rechaza con un error que explica qué hacer.
8
+ * ## Qué cambió y por qué
10
9
  *
11
- * El guard tiene una salida: si el archivo es claramente correcto y el
12
- * modelo insiste, el scope de la card se puede ampliar. Pero el default es
13
- * denegar.
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
- * Glob mínimo a regex. Soporta `*`, `**` y `?`.
74
+ * Extrae TODOS los paths que una tool de escritura quiere tocar.
22
75
  *
23
- * El orden de los reemplazos importa: el `?` se convierte ANTES de insertar
24
- * los patrones de `**`, porque el grupo insertado contiene un `?` literal
25
- * que, si se convierte después, se rompe y deja de matchear.
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;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAQ/C,MAAM,WAAW,iBAAiB;IAChC,qDAAqD;IACrD,OAAO,EAAE,OAAO,CAAA;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAWhD;AAED,kDAAkD;AAClD,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAM3E;AAED,6DAA6D;AAC7D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,SAAS,CAe3F;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAqC,IAE/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,CAkDjB"}
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"}
@@ -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
- * Cuando una sesión intenta escribir un archivo que no está en el scope de
9
- * su card, la operación se rechaza con un error que explica qué hacer.
8
+ * ## Qué cambió y por qué
10
9
  *
11
- * El guard tiene una salida: si el archivo es claramente correcto y el
12
- * modelo insiste, el scope de la card se puede ampliar. Pero el default es
13
- * denegar.
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 path from "node:path";
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
- * Glob mínimo a regex. Soporta `*`, `**` y `?`.
54
+ * Tools que escriben UN archivo.
22
55
  *
23
- * El orden de los reemplazos importa: el `?` se convierte ANTES de insertar
24
- * los patrones de `**`, porque el grupo insertado contiene un `?` literal
25
- * que, si se convierte después, se rompe y deja de matchear.
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
- export function globToRegex(glob) {
28
- const escaped = glob
29
- .replace(/[.+^${}()|[\]\\]/g, "\\$&")
30
- // `?` primero: los patrones insertados después contienen `?` literal.
31
- .replace(/\?/g, ".")
32
- .replace(/\*\*\//g, "\u0000")
33
- .replace(/\*\*/g, "\u0001")
34
- .replace(/\*/g, "[^/]*")
35
- .replace(/\u0000/g, "(?:.*/)?")
36
- .replace(/\u0001/g, ".*");
37
- return new RegExp(`^${escaped}$`);
38
- }
39
- /** ¿El path cae dentro de alguno de los globs? */
40
- export function matchesScope(relativePath, globs) {
41
- const normalized = relativePath.replace(/\\/g, "/").replace(/^\.\//, "");
42
- return globs.some((glob) => {
43
- if (glob === "**")
44
- return true;
45
- return globToRegex(glob).test(normalized);
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
- /** Extrae el path del argumento de una tool de escritura. */
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
- const candidates = ["filePath", "path", "file", "target", "notebook_path"];
51
- for (const key of candidates) {
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
- // El tool `patch` puede traer los paths dentro de un patch estructurado.
57
- if (tool === "patch" || tool === "apply_patch") {
58
- const patch = args.patch ?? args.diff;
59
- if (typeof patch === "string") {
60
- const m = /^---+\s+(.+)$/m.exec(patch);
61
- if (m?.[1])
62
- return m[1].trim();
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
- if (!output?.args)
261
+ const args = output?.args;
262
+ if (!args || typeof args !== "object")
70
263
  return;
71
- if (!WRITE_TOOLS.has(input.tool))
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 = office.sessionCard(state, input.sessionID);
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 rawPath = extractPath(input.tool, output.args);
81
- if (!rawPath)
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
- const absolute = path.isAbsolute(rawPath)
84
- ? rawPath
85
- : path.join(office.paths.projectRoot, rawPath);
86
- const relative = path.relative(office.paths.projectRoot, absolute).replace(/\\/g, "/");
87
- // Los artefactos de la oficina siempre están permitidos: son el canal.
88
- if (relative.startsWith(".oficina/"))
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
- if (!matchesScope(relative, mayTouch)) {
97
- throw new Error(`[OFICINA] Scope violado: \`${relative}\` está fuera del scope de la card ${card.id}. ` +
98
- `Podés tocar: ${mayTouch.join(", ")}. ` +
99
- `Si el archivo es necesario, pedí por el bus que se amplíe el scope, o pedí ayuda a un peer que lo cubra.`);
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":"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"}
1
+ {"version":3,"file":"scopeGuard.js","sourceRoot":"","sources":["../../src/hooks/scopeGuard.ts"],"names":[],"mappings":"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"}
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;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAA;AAW9D,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;CACvB;AAED,eAAO,MAAM,aAAa,EAAE,MAmF3B,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"}
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"}