oficina-opencode 3.0.5 → 3.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 (145) hide show
  1. package/README.md +240 -208
  2. package/commands/oficina.md +7 -6
  3. package/dashboard/.dom-check.html +1257 -0
  4. package/dashboard/README-DASHBOARD.md +64 -0
  5. package/dashboard/assets/factory.css +1543 -0
  6. package/dashboard/assets/tokens.css +208 -0
  7. package/dashboard/build-kanban-data.mjs +279 -0
  8. package/dashboard/dashboard.css +753 -0
  9. package/dashboard/dashboard.html +121 -0
  10. package/dashboard/dashboard.js +610 -0
  11. package/dashboard/data/snapshot.json +883 -0
  12. package/dashboard/debate.html +134 -0
  13. package/dashboard/factory/build-snapshot.mjs +89 -0
  14. package/dashboard/factory/factory-app.js +1185 -0
  15. package/dashboard/factory/factory-core.js +541 -0
  16. package/dashboard/factory/snapshot.js +850 -0
  17. package/dashboard/factory.html +350 -0
  18. package/dashboard/kanban-data.json +671 -0
  19. package/dashboard/kanban-source.js +643 -0
  20. package/dashboard/kanban.check.mjs +454 -0
  21. package/dashboard/kanban.html +1257 -0
  22. package/dashboard/leadership.html +1008 -0
  23. package/dashboard/lib/debate-app.js +1149 -0
  24. package/dashboard/lib/debate-core.js +698 -0
  25. package/dashboard/lib/debate-data.js +163 -0
  26. package/dashboard/lib/debate-demo.js +110 -0
  27. package/dashboard/lib/debate.css +1155 -0
  28. package/dashboard/lib/leadership-model.js +946 -0
  29. package/dashboard/probe.mjs +35 -0
  30. package/dashboard/scripts/serve.mjs +122 -0
  31. package/dashboard/scripts/snapshot-data.mjs +93 -0
  32. package/dashboard/scripts/snapshot.mjs +28 -0
  33. package/dashboard/server.mjs +242 -0
  34. package/dashboard/shot.mjs +54 -0
  35. package/dashboard/shots/desktop-gates.png +0 -0
  36. package/dashboard/shots/desktop-light.png +0 -0
  37. package/dashboard/shots/desktop-real.png +0 -0
  38. package/dashboard/shots/mobile.png +0 -0
  39. package/dashboard/test/factory-core.test.mjs +244 -0
  40. package/dashboard/tests/debate-core.test.mjs +336 -0
  41. package/dashboard/tests/leadership-model.test.mjs +404 -0
  42. package/dist/cli.js +148 -26
  43. package/dist/cli.js.map +1 -1
  44. package/dist/core/bus.js +3 -3
  45. package/dist/core/bus.js.map +1 -1
  46. package/dist/core/catalog.d.ts +9 -1
  47. package/dist/core/catalog.d.ts.map +1 -1
  48. package/dist/core/catalog.js +77 -2
  49. package/dist/core/catalog.js.map +1 -1
  50. package/dist/core/dashboard.d.ts +33 -0
  51. package/dist/core/dashboard.d.ts.map +1 -0
  52. package/dist/core/dashboard.js +115 -0
  53. package/dist/core/dashboard.js.map +1 -0
  54. package/dist/core/dispatch.d.ts +1 -1
  55. package/dist/core/dispatch.d.ts.map +1 -1
  56. package/dist/core/dispatch.js +84 -12
  57. package/dist/core/dispatch.js.map +1 -1
  58. package/dist/core/docsync.d.ts +0 -9
  59. package/dist/core/docsync.d.ts.map +1 -1
  60. package/dist/core/docsync.js +12 -15
  61. package/dist/core/docsync.js.map +1 -1
  62. package/dist/core/environment.d.ts +28 -0
  63. package/dist/core/environment.d.ts.map +1 -0
  64. package/dist/core/environment.js +80 -0
  65. package/dist/core/environment.js.map +1 -0
  66. package/dist/core/factory.d.ts +16 -0
  67. package/dist/core/factory.d.ts.map +1 -1
  68. package/dist/core/factory.js +143 -0
  69. package/dist/core/factory.js.map +1 -1
  70. package/dist/core/fsx.d.ts +20 -2
  71. package/dist/core/fsx.d.ts.map +1 -1
  72. package/dist/core/fsx.js +10 -6
  73. package/dist/core/fsx.js.map +1 -1
  74. package/dist/core/gates.d.ts +23 -1
  75. package/dist/core/gates.d.ts.map +1 -1
  76. package/dist/core/gates.js +83 -8
  77. package/dist/core/gates.js.map +1 -1
  78. package/dist/core/leases.d.ts.map +1 -1
  79. package/dist/core/leases.js +4 -1
  80. package/dist/core/leases.js.map +1 -1
  81. package/dist/core/mesa.d.ts +1 -6
  82. package/dist/core/mesa.d.ts.map +1 -1
  83. package/dist/core/mesa.js +1 -6
  84. package/dist/core/mesa.js.map +1 -1
  85. package/dist/core/office.d.ts +3 -29
  86. package/dist/core/office.d.ts.map +1 -1
  87. package/dist/core/office.js +77 -90
  88. package/dist/core/office.js.map +1 -1
  89. package/dist/core/paths.d.ts.map +1 -1
  90. package/dist/core/paths.js +6 -1
  91. package/dist/core/paths.js.map +1 -1
  92. package/dist/core/retry.d.ts +2 -8
  93. package/dist/core/retry.d.ts.map +1 -1
  94. package/dist/core/retry.js +3 -34
  95. package/dist/core/retry.js.map +1 -1
  96. package/dist/core/roster.js +3 -3
  97. package/dist/core/roster.js.map +1 -1
  98. package/dist/core/sandbox.d.ts +38 -1
  99. package/dist/core/sandbox.d.ts.map +1 -1
  100. package/dist/core/sandbox.js +119 -15
  101. package/dist/core/sandbox.js.map +1 -1
  102. package/dist/core/state.d.ts +2 -2
  103. package/dist/core/state.d.ts.map +1 -1
  104. package/dist/core/state.js +5 -33
  105. package/dist/core/state.js.map +1 -1
  106. package/dist/core/stores.d.ts +3 -13
  107. package/dist/core/stores.d.ts.map +1 -1
  108. package/dist/core/stores.js +8 -32
  109. package/dist/core/stores.js.map +1 -1
  110. package/dist/core/systemPrompt.d.ts.map +1 -1
  111. package/dist/core/systemPrompt.js +4 -1
  112. package/dist/core/systemPrompt.js.map +1 -1
  113. package/dist/core/tripwire.d.ts +22 -8
  114. package/dist/core/tripwire.d.ts.map +1 -1
  115. package/dist/core/tripwire.js +71 -26
  116. package/dist/core/tripwire.js.map +1 -1
  117. package/dist/core/types.d.ts +6 -14
  118. package/dist/core/types.d.ts.map +1 -1
  119. package/dist/core/types.js +11 -3
  120. package/dist/core/types.js.map +1 -1
  121. package/dist/hooks/scopeGuard.d.ts +15 -1
  122. package/dist/hooks/scopeGuard.d.ts.map +1 -1
  123. package/dist/hooks/scopeGuard.js +88 -73
  124. package/dist/hooks/scopeGuard.js.map +1 -1
  125. package/dist/tools/index.d.ts +9 -1
  126. package/dist/tools/index.d.ts.map +1 -1
  127. package/dist/tools/index.js +29 -81
  128. package/dist/tools/index.js.bak +972 -0
  129. package/dist/tools/index.js.map +1 -1
  130. package/dist/v1.d.ts.map +1 -1
  131. package/dist/v1.js +30 -36
  132. package/dist/v1.js.map +1 -1
  133. package/dist/v2.d.ts +5 -0
  134. package/dist/v2.d.ts.map +1 -1
  135. package/dist/v2.js +79 -46
  136. package/dist/v2.js.bak +517 -0
  137. package/dist/v2.js.map +1 -1
  138. package/docs/GARANTIAS.md +2 -2
  139. package/docs/PRUEBA-E2E.md +4 -4
  140. package/docs/QUE-ES.md +4 -5
  141. package/docs/SEGURIDAD-REPO.md +83 -0
  142. package/docs/assets/banner.svg +42 -0
  143. package/docs/catalog-facts.json +3 -3
  144. package/docs/superpowers/specs/2026-10-29-factory-skill-creator-and-remove-budget.md +182 -0
  145. package/package.json +14 -6
@@ -0,0 +1,134 @@
1
+ <!doctype html>
2
+ <html lang="es" data-theme="dark">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Debate · Oficina de Agents</title>
7
+ <meta
8
+ name="description"
9
+ content="Panel de debate/brainstorming trazable: pedidos de ayuda broadcast (HELP_REQUEST a '*') y sus respuestas anidadas."
10
+ />
11
+ <link rel="stylesheet" href="lib/debate.css" />
12
+ </head>
13
+ <body>
14
+ <a class="skip-link" href="#threads">Saltar al debate</a>
15
+
16
+ <header class="topbar">
17
+ <div class="brand">
18
+ <span class="logo" aria-hidden="true">◍</span>
19
+ <div class="brand-text">
20
+ <h1>Debate</h1>
21
+ <p class="sub">HELP_REQUEST broadcast · respuestas anidadas · trazabilidad</p>
22
+ </div>
23
+ </div>
24
+ <div class="topbar-tools">
25
+ <span id="conn" class="conn conn-live" role="status">en vivo</span>
26
+ <span id="updated" class="muted">sin datos</span>
27
+ <button type="button" class="ghost" data-action="pause" aria-pressed="false" title="Pausar/reanudar la lectura (p)">Pausar</button>
28
+ <button type="button" class="ghost" data-action="reload" title="Refrescar ahora (r)">Refrescar</button>
29
+ <button type="button" class="ghost icon" data-action="theme" aria-label="Cambiar tema claro/oscuro" title="Tema claro/oscuro">◐</button>
30
+ <button type="button" class="ghost icon" data-action="help" aria-label="Ayuda y atajos" title="Ayuda y atajos (?)">?</button>
31
+ </div>
32
+ </header>
33
+
34
+ <div id="banner" class="banner" role="alert" hidden></div>
35
+
36
+ <section class="stats" aria-label="Resumen de hilos">
37
+ <div class="stat">
38
+ <span class="stat-label">Hilos</span>
39
+ <strong id="stat-all">0</strong>
40
+ </div>
41
+ <div class="stat stat-pending">
42
+ <span class="stat-label">Esperando</span>
43
+ <strong id="stat-pending">0</strong>
44
+ </div>
45
+ <div class="stat stat-progress">
46
+ <span class="stat-label">En curso</span>
47
+ <strong id="stat-progress">0</strong>
48
+ </div>
49
+ <div class="stat stat-done">
50
+ <span class="stat-label">Completados</span>
51
+ <strong id="stat-done">0</strong>
52
+ </div>
53
+ <div class="stat stat-declined">
54
+ <span class="stat-label">Rechazados</span>
55
+ <strong id="stat-declined">0</strong>
56
+ </div>
57
+ </section>
58
+
59
+ <div class="toolbar">
60
+ <div class="search">
61
+ <label class="sr-only" for="filter-q">Buscar en hilos y respuestas</label>
62
+ <input
63
+ id="filter-q"
64
+ type="search"
65
+ autocomplete="off"
66
+ placeholder="Buscar agente, card o texto ( / )"
67
+ />
68
+ </div>
69
+ <label class="sr-only" for="filter-status">Filtrar por estado</label>
70
+ <select id="filter-status">
71
+ <option value="all">Todos (0)</option>
72
+ <option value="pending">Esperando (0)</option>
73
+ <option value="accepted">Aceptados (0)</option>
74
+ <option value="partial">Parciales (0)</option>
75
+ <option value="declined">Rechazados (0)</option>
76
+ <option value="completed">Completados (0)</option>
77
+ </select>
78
+ <label class="sr-only" for="filter-agent">Filtrar por agente</label>
79
+ <select id="filter-agent">
80
+ <option value="">Todos los agentes</option>
81
+ </select>
82
+ <span class="spacer"></span>
83
+ <button type="button" class="ghost" data-action="expand-all" title="Abrir todos los hilos (e)">Expandir todo</button>
84
+ <button type="button" class="ghost" data-action="collapse-all" title="Cerrar todos los hilos (x)">Colapsar todo</button>
85
+ </div>
86
+
87
+ <p id="count-label" class="count-label">0 hilos</p>
88
+
89
+ <main id="threads" class="threads" aria-busy="true" aria-label="Hilos de debate"></main>
90
+ <div id="empty" class="empty"></div>
91
+
92
+ <footer id="footer-meta" class="footer"></footer>
93
+
94
+ <div id="live" class="sr-only" role="status" aria-live="polite" aria-atomic="false"></div>
95
+
96
+ <dialog id="help" class="help" aria-labelledby="help-title">
97
+ <h2 id="help-title">Cómo usar el panel de debate</h2>
98
+ <ul class="help-list">
99
+ <li><strong>Qué muestra:</strong> cada <code>HELP_REQUEST</code> dirigido a <code>["*"]</code> (o a varios agentes) abre un hilo. Debajo se anidan las respuestas: <code>HELP_ACCEPT</code>, <code>HELP_DECLINE</code>, <code>HELP_PARTIAL</code> y <code>HELP_QUESTION</code>, más el <code>STATUS</code>/<code>ANSWER</code> con el que se cierra.</li>
100
+ <li><strong>Estado:</strong> esperando → aceptado / parcial / rechazado → completado. Se completa cuando el hilo recibe una señal de cierre o el TTL del pedido vence.</li>
101
+ <li><strong>Datos en vivo:</strong> corré <code>node dashboard/server.mjs</code> y abrí <code>http://127.0.0.1:7788/debate.html</code>. El server lee <code>.oficina/bus/</code> en modo sólo lectura.</li>
102
+ <li><strong>Sin server:</strong> arrastrá los JSON de <code>.oficina/bus/peer/</code> sobre la página, o usá <code>?demo=1</code> para ver datos sintéticos.</li>
103
+ </ul>
104
+ <h3>Atajos</h3>
105
+ <dl class="keys">
106
+ <dt><kbd>/</kbd></dt><dd>Buscar</dd>
107
+ <dt><kbd>↑</kbd> <kbd>↓</kbd></dt><dd>Moverse entre hilos</dd>
108
+ <dt><kbd>Enter</kbd></dt><dd>Abrir / cerrar el hilo enfocado</dd>
109
+ <dt><kbd>e</kbd> / <kbd>x</kbd></dt><dd>Expandir / colapsar todo</dd>
110
+ <dt><kbd>p</kbd></dt><dd>Pausar / reanudar actualización</dd>
111
+ <dt><kbd>r</kbd></dt><dd>Refrescar</dd>
112
+ <dt><kbd>?</kbd></dt><dd>Esta ayuda</dd>
113
+ <dt><kbd>Esc</kbd></dt><dd>Cerrar ayuda / salir del buscador</dd>
114
+ </dl>
115
+ <form method="dialog" class="help-actions">
116
+ <button type="button" class="ghost" data-action="pick-files">Cargar JSON del bus</button>
117
+ <button type="button" class="ghost" data-action="demo">Ver demo</button>
118
+ <button value="close" type="submit">Cerrar</button>
119
+ </form>
120
+ </dialog>
121
+
122
+ <div id="dropzone" class="dropzone" hidden>
123
+ <p>Soltá los JSON del bus (peer/, coord-flow/…) para construir el debate</p>
124
+ </div>
125
+
126
+ <label class="sr-only" for="file-input">Archivos JSON del bus</label>
127
+ <input id="file-input" class="sr-only" type="file" accept="application/json,.json" multiple />
128
+
129
+ <script src="lib/debate-core.js"></script>
130
+ <script src="lib/debate-data.js"></script>
131
+ <script src="lib/debate-demo.js"></script>
132
+ <script src="lib/debate-app.js"></script>
133
+ </body>
134
+ </html>
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * build-snapshot.mjs — embeds a read-only snapshot of .oficina/ into
4
+ * dashboard/factory/snapshot.js so factory.html works from file:// (where
5
+ * fetch() and ES modules are blocked by CORS).
6
+ *
7
+ * node dashboard/factory/build-snapshot.mjs
8
+ *
9
+ * Reads: .oficina/state.json, .oficina/roster.json, .opencode/agents/*.md
10
+ * Writes: dashboard/factory/snapshot.js (only file written)
11
+ *
12
+ * Run it again whenever you want the offline snapshot refreshed; the live mode
13
+ * (dashboard/serve.mjs) always reads the real files.
14
+ */
15
+ import { readFile, writeFile, readdir, stat } from "node:fs/promises"
16
+ import { join, resolve, dirname, basename } from "node:path"
17
+ import { fileURLToPath } from "node:url"
18
+
19
+ const here = dirname(fileURLToPath(import.meta.url))
20
+ const repoRoot = resolve(here, "..", "..")
21
+ const officeDir = join(repoRoot, ".oficina")
22
+ const agentsDir = join(repoRoot, ".opencode", "agents")
23
+ const outFile = join(here, "snapshot.js")
24
+
25
+ async function readJson(path) {
26
+ return JSON.parse(await readFile(path, "utf8"))
27
+ }
28
+
29
+ /** Drop fields that are huge and irrelevant for the dashboard. */
30
+ function slimRoster(roster) {
31
+ const agents = {}
32
+ for (const [id, agent] of Object.entries(roster.agents || {})) {
33
+ const source = agent.source ? { ...agent.source } : null
34
+ if (source) delete source.sourcePrompt
35
+ agents[id] = { ...agent, source }
36
+ delete agents[id].raw
37
+ }
38
+ return { ...roster, agents }
39
+ }
40
+
41
+ const [state, rosterRaw] = await Promise.all([
42
+ readJson(join(officeDir, "state.json")),
43
+ readJson(join(officeDir, "roster.json")),
44
+ ])
45
+ const roster = slimRoster(rosterRaw)
46
+
47
+ let files = []
48
+ try {
49
+ files = (await readdir(agentsDir)).filter((name) => name.endsWith(".md"))
50
+ } catch {
51
+ files = []
52
+ }
53
+
54
+ const fichas = {}
55
+ for (const name of files.sort()) {
56
+ const full = join(agentsDir, name)
57
+ const [content, info] = await Promise.all([readFile(full, "utf8"), stat(full)])
58
+ fichas[`.opencode/agents/${name}`] = {
59
+ name,
60
+ bytes: info.size,
61
+ modifiedAt: info.mtime.toISOString(),
62
+ content,
63
+ }
64
+ }
65
+
66
+ const snapshot = {
67
+ source: "embedded-snapshot",
68
+ capturedAt: new Date().toISOString(),
69
+ projectRoot: repoRoot,
70
+ state,
71
+ roster,
72
+ catalogo: Object.keys(fichas).map((path) => ({
73
+ path,
74
+ name: basename(path),
75
+ bytes: fichas[path].bytes,
76
+ modifiedAt: fichas[path].modifiedAt,
77
+ })),
78
+ fichas,
79
+ }
80
+
81
+ const banner =
82
+ "/* GENERADO por dashboard/factory/build-snapshot.mjs — no editar a mano. */\n"
83
+ const body = `${banner}window.__FACTORY_SNAPSHOT__ = ${JSON.stringify(snapshot, null, 2)};\n`
84
+ await writeFile(outFile, body, "utf8")
85
+
86
+ const cards = Object.keys(state.cards || {}).length
87
+ console.log(
88
+ `snapshot.js escrito: ${cards} cards, ${Object.keys(roster.agents || {}).length} agentes, ${Object.keys(fichas).length} fichas (${(body.length / 1024).toFixed(1)} KiB)`,
89
+ )