@kikedealba/recap 0.9.1 → 0.11.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 +68 -37
- package/Resources/ask-prompt.md +1 -1
- package/Resources/wrapup-prompt.md +1 -1
- package/dist/bita/client.js +39 -51
- package/dist/bita/hook.js +6 -0
- package/dist/bita/proposals.js +30 -32
- package/dist/bita/wrapup.js +41 -22
- package/dist/cli/commands/ask.js +4 -6
- package/dist/cli/commands/hook.js +15 -0
- package/dist/cli/commands/proposals.js +4 -6
- package/dist/cli/commands/query.js +11 -3
- package/dist/cli/commands/watch.js +109 -0
- package/dist/cli/router.js +3 -0
- package/dist/live/context.js +47 -20
- package/dist/live/worker.js +2 -6
- package/dist/pipeline/pipeline.js +11 -7
- package/dist/setup/integration.js +24 -29
- package/package.json +3 -4
- package/skills/recap/SKILL.md +77 -137
- package/skills/recap/live.md +31 -0
- package/skills/recap/proposals.md +19 -0
- package/skills/recap/storage.md +16 -0
- package/skills/recap/wrapup.md +49 -0
- package/{commands/recap-ask.md → skills/recap-ask/SKILL.md} +2 -0
- package/{commands/recap-list.md → skills/recap-list/SKILL.md} +2 -0
- package/{commands/recap-proposals.md → skills/recap-proposals/SKILL.md} +6 -2
- package/{commands/recap-start.md → skills/recap-start/SKILL.md} +2 -0
- package/{commands/recap-status.md → skills/recap-status/SKILL.md} +2 -0
- package/skills/recap-stop/SKILL.md +73 -0
- package/{commands/recap-summarize.md → skills/recap-summarize/SKILL.md} +2 -0
- package/commands/recap-stop.md +0 -69
|
@@ -3,9 +3,6 @@ import path from 'node:path';
|
|
|
3
3
|
import { agents } from '@kikedealba/kit';
|
|
4
4
|
import { defineManifest, isInstalled, readManifest, registerTool } from '@kikedealba/kit/registry';
|
|
5
5
|
import { bitaCommand } from "../bita/client.js";
|
|
6
|
-
import { readText } from "../core/fsutil.js";
|
|
7
|
-
import { isRecord } from "../core/json.js";
|
|
8
|
-
import { home } from "../core/paths.js";
|
|
9
6
|
import { stableCommand } from "../core/self.js";
|
|
10
7
|
import { HOOK_EVENTS, MEETING_KINDS } from "../bita/hook.js";
|
|
11
8
|
import { PACKAGE_ROOT, VERSION } from "../version.js";
|
|
@@ -47,24 +44,29 @@ export async function bitaLinked(config) {
|
|
|
47
44
|
return false;
|
|
48
45
|
return (await bitaCommand(config)) !== null;
|
|
49
46
|
}
|
|
50
|
-
export
|
|
51
|
-
|
|
47
|
+
export const MAIN_SKILL = 'recap';
|
|
48
|
+
export const CLAUDE_PLUGIN = { marketplace: 'KikeDeAlba/recap', marketplaceName: 'recap', plugin: 'recap' };
|
|
49
|
+
export function userSkillSources() {
|
|
50
|
+
const dir = path.join(PACKAGE_ROOT, 'skills');
|
|
52
51
|
let names = [];
|
|
53
52
|
try {
|
|
54
|
-
names = readdirSync(dir
|
|
53
|
+
names = readdirSync(dir, { withFileTypes: true })
|
|
54
|
+
.filter((entry) => entry.isDirectory() && entry.name.startsWith(`${MAIN_SKILL}-`))
|
|
55
|
+
.map((entry) => entry.name)
|
|
56
|
+
.sort();
|
|
55
57
|
}
|
|
56
58
|
catch {
|
|
57
59
|
return [];
|
|
58
60
|
}
|
|
59
|
-
return names.map((name) => ({ name
|
|
61
|
+
return names.map((name) => ({ name, dir: path.join(dir, name) }));
|
|
60
62
|
}
|
|
61
63
|
export function integration() {
|
|
62
64
|
return {
|
|
63
65
|
tool: 'recap',
|
|
64
66
|
version: VERSION,
|
|
65
67
|
description: 'Record meetings and turn them into minutes with recap',
|
|
66
|
-
skills: [{ name:
|
|
67
|
-
|
|
68
|
+
skills: [{ name: MAIN_SKILL, dir: path.join(PACKAGE_ROOT, 'skills', MAIN_SKILL) }],
|
|
69
|
+
userSkills: userSkillSources(),
|
|
68
70
|
claude: {
|
|
69
71
|
permissions: {
|
|
70
72
|
allow: ['Bash(recap status:*)', 'Bash(recap list:*)', 'Bash(recap show:*)', 'Bash(recap wait:*)', 'Bash(recap prompt:*)', 'Bash(recap --version)'],
|
|
@@ -72,19 +74,9 @@ export function integration() {
|
|
|
72
74
|
},
|
|
73
75
|
};
|
|
74
76
|
}
|
|
75
|
-
export function
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
if (text === null)
|
|
79
|
-
return false;
|
|
80
|
-
try {
|
|
81
|
-
const value = JSON.parse(text);
|
|
82
|
-
const plugins = isRecord(value) && isRecord(value['plugins']) ? value['plugins'] : isRecord(value) ? value : {};
|
|
83
|
-
return Object.keys(plugins).some((key) => key.startsWith('recap@'));
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
return text.includes('"recap@');
|
|
87
|
-
}
|
|
77
|
+
export function legacyClaudeIntegration() {
|
|
78
|
+
const { claude: _permissions, ...base } = integration();
|
|
79
|
+
return { ...base, commands: (base.userSkills ?? []).map((skill) => ({ name: skill.name, file: path.join(skill.dir, 'SKILL.md') })) };
|
|
88
80
|
}
|
|
89
81
|
export function parseAgents(raw) {
|
|
90
82
|
if (raw === undefined || raw === 'detected')
|
|
@@ -97,16 +89,19 @@ export function parseAgents(raw) {
|
|
|
97
89
|
throw new Error(`Unknown agent ${invalid.join(', ')}; use ${agents.AGENTS.join(', ')}, detected, all or none`);
|
|
98
90
|
return wanted;
|
|
99
91
|
}
|
|
100
|
-
export async function installAgents(choice,
|
|
92
|
+
export async function installAgents(choice, options = {}) {
|
|
101
93
|
if (choice === 'none')
|
|
102
94
|
return [];
|
|
103
|
-
|
|
95
|
+
const list = choice === 'detected' ? await agents.detectAgents(options.ctx, agents.agentHomes(options.ctx, options.homes), options.locate) : choice === 'all' ? [...agents.AGENTS] : choice;
|
|
104
96
|
const steps = [];
|
|
105
|
-
if (list.includes('claude')
|
|
106
|
-
|
|
107
|
-
steps.push(
|
|
97
|
+
if (list.includes('claude')) {
|
|
98
|
+
const plugin = await agents.installClaudePlugin(CLAUDE_PLUGIN, options);
|
|
99
|
+
steps.push(...plugin);
|
|
100
|
+
if (plugin.every((step) => step.state === 'installed' || step.state === 'present'))
|
|
101
|
+
steps.push(...(await agents.removeLegacyClaude(legacyClaudeIntegration(), options)));
|
|
108
102
|
}
|
|
109
|
-
|
|
103
|
+
const others = list.filter((agent) => agent !== 'claude');
|
|
104
|
+
if (others.length === 0)
|
|
110
105
|
return steps;
|
|
111
|
-
return [...steps, ...(await agents.installIntegration(integration(), {
|
|
106
|
+
return [...steps, ...(await agents.installIntegration(integration(), { ...options, agents: others }))];
|
|
112
107
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kikedealba/recap",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Meeting recorder CLI: local transcription with whisper.cpp, minutes written by Claude Code, live answers and
|
|
3
|
+
"version": "0.11.0",
|
|
4
|
+
"description": "Meeting recorder CLI: local transcription with whisper.cpp, minutes written by Claude Code, live answers, bita timers and inkwell docs.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Jesus Enrique De Alba Gaytan",
|
|
7
7
|
"homepage": "https://github.com/KikeDeAlba/recap#readme",
|
|
@@ -35,7 +35,6 @@
|
|
|
35
35
|
"dist",
|
|
36
36
|
"Resources/*.md",
|
|
37
37
|
"skills",
|
|
38
|
-
"commands",
|
|
39
38
|
"README.md",
|
|
40
39
|
"LICENSE"
|
|
41
40
|
],
|
|
@@ -50,7 +49,7 @@
|
|
|
50
49
|
"recap": "node src/bin/recap.ts"
|
|
51
50
|
},
|
|
52
51
|
"dependencies": {
|
|
53
|
-
"@kikedealba/kit": "^0.
|
|
52
|
+
"@kikedealba/kit": "^0.3.0"
|
|
54
53
|
},
|
|
55
54
|
"devDependencies": {
|
|
56
55
|
"@types/node": "^24.0.0",
|
package/skills/recap/SKILL.md
CHANGED
|
@@ -6,21 +6,26 @@ description: Graba reuniones con la CLI `recap` y las convierte en minuta (resum
|
|
|
6
6
|
# recap
|
|
7
7
|
|
|
8
8
|
`recap` graba reuniones (en macOS, con Recap.app) y las procesa localmente en
|
|
9
|
-
macOS, Windows y Linux.
|
|
10
|
-
|
|
9
|
+
macOS, Windows y Linux. Cada reunión es una carpeta bajo `~/Recap` (o la raíz
|
|
10
|
+
configurada) con `meeting.json`, la grabación, `transcript.md`, `frames/` y
|
|
11
11
|
`summary.md`.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
la
|
|
15
|
-
|
|
13
|
+
Quién hace qué: bita mide el tiempo, recap graba y escribe la minuta, inkwell
|
|
14
|
+
guarda la documentación, tally vuelca el tiempo a Jira y atl habla con Jira y
|
|
15
|
+
Confluence. Este es el único lugar donde se describe el flujo de una reunión;
|
|
16
|
+
las demás herramientas enlazan aquí.
|
|
16
17
|
|
|
17
18
|
Todos los comandos aceptan `--json` y devuelven un sobre
|
|
18
19
|
`{schemaVersion, ok, command, data, error}`. Usa `--json` siempre que vayas a
|
|
19
20
|
leer el resultado; el texto plano es para mostrarlo tal cual.
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
Fuera de macOS no se puede grabar (`start` falla con `CAPTURE_UNAVAILABLE`):
|
|
23
|
+
la reunión se graba con otra app y se procesa con
|
|
24
|
+
`recap import <archivo> [--title "…"] [--in-person|--remote] --json`.
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
## Modo
|
|
27
|
+
|
|
28
|
+
Hay que elegirlo siempre; no tiene valor por defecto.
|
|
24
29
|
|
|
25
30
|
| Modo | Flag | Cuándo |
|
|
26
31
|
|---|---|---|
|
|
@@ -28,132 +33,49 @@ Hay que elegir el modo siempre; no tiene valor por defecto.
|
|
|
28
33
|
| Presencial | `--in-person` | En sala, en oficina, en persona, junta física, comida, "aquí con" |
|
|
29
34
|
|
|
30
35
|
En remota se graba pantalla, audio del sistema y micrófono; en presencial solo
|
|
31
|
-
el micrófono
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
##
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
recap
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
recap
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
| `DEPENDENCY_MISSING`, `MODEL_MISSING` | Falta ffmpeg, whisper-cli, claude o el modelo | `recap setup --install-deps` |
|
|
75
|
-
| `CAPTURE_UNAVAILABLE` | No hay grabador en este equipo (Windows, Linux, o falta Recap.app) | Graba con otra app y usa `recap import <archivo>`; en mac, `recap setup` |
|
|
76
|
-
|
|
77
|
-
## Con bita
|
|
78
|
-
|
|
79
|
-
Si `recap status --json` trae `data.bitaLinked: true` (recap está suscrito a
|
|
80
|
-
los eventos de bita desde `recap setup`), **arranca y para las reuniones desde
|
|
81
|
-
bita**, no desde recap: así el tiempo queda medido y la grabación sigue al
|
|
82
|
-
contador.
|
|
83
|
-
|
|
84
|
-
```sh
|
|
85
|
-
bita start "<título>" --kind remote-meeting
|
|
86
|
-
bita start "<título>" --kind in-person-meeting
|
|
87
|
-
bita stop <id> --json # sin --did y sin escribir la página
|
|
88
|
-
recap wait --bita-entry <id> --json # espera a que todo quede listo
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
Al parar, recap hace todo lo demás sin que nadie lo pida:
|
|
92
|
-
|
|
93
|
-
- transcribe y escribe la minuta;
|
|
94
|
-
- le pone al contador un título real, si el que tenía era genérico;
|
|
95
|
-
- le asigna el proyecto si no tenía y la conversación lo deja claro;
|
|
96
|
-
- crea la página en ese proyecto, o agrega una sección a la que ya tenía, y la escribe;
|
|
97
|
-
- pasa pendientes y preguntas abiertas al backlog;
|
|
98
|
-
- deja la minuta en la sección «Reunión» de la entrada.
|
|
99
|
-
|
|
100
|
-
El resultado está en `data.wrapup` de `recap wait`. Si `wrapup.projectResolved`
|
|
101
|
-
es false, pregunta el proyecto y aplícalo con `bita amend`, y mueve la página y
|
|
102
|
-
el backlog con inkwell si está instalado (`inkwell page move --project`,
|
|
103
|
-
`inkwell backlog edit --project`) o, si no, con `bita docs page move --project`
|
|
104
|
-
y `bita backlog edit --project`.
|
|
105
|
-
|
|
106
|
-
Las páginas, las propuestas y el backlog se escriben con inkwell cuando está
|
|
107
|
-
instalado y ya migró los documentos de bita; si no, con `bita docs`/`bita backlog`.
|
|
108
|
-
|
|
109
|
-
## En vivo
|
|
110
|
-
|
|
111
|
-
Mientras se graba, recap transcribe por tramos de 5 a 20 s en
|
|
112
|
-
`live/transcript.jsonl` (una línea `{startMs, endMs, channel, text}`; `mic` es
|
|
113
|
-
Sala y `system` Remotos). Es aproximada: la transcripción de después del stop
|
|
114
|
-
(`transcript.md`) sigue siendo la fuente de verdad.
|
|
115
|
-
|
|
116
|
-
Para responder una pregunta que hicieron en la reunión, con las páginas de bita
|
|
117
|
-
y los repos del proyecto (`bita project repo ls`):
|
|
118
|
-
|
|
119
|
-
```sh
|
|
120
|
-
recap ask --active --json # la última pregunta de la transcripción
|
|
121
|
-
recap ask --active --question "¿cómo se despliega X?" --json
|
|
122
|
-
recap ask --meeting <id> --question "..." --json-stream # eventos question/progress/delta/source/done
|
|
123
|
-
recap ask --sources --project <p> --json # qué consultaría, sin llamar a claude
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
La respuesta lleva `found` y `sources` (página, `archivo:línea` o commit) y se
|
|
127
|
-
guarda en `live/answers.jsonl`. Con `found: false` no está documentado: no lo
|
|
128
|
-
completes por tu cuenta. Se configura con `recap config get|set`
|
|
129
|
-
(`live.enabled`, `live.openWindow`, `live.proposals`, `live.maxChunkSeconds`,
|
|
130
|
-
`live.assistModel`, `live.autoAsk`, `live.autoAskModel`,
|
|
131
|
-
`live.autoAskMinSeconds`).
|
|
132
|
-
|
|
133
|
-
Con `live.autoAsk` (encendido por omisión), el live-worker detecta solo las
|
|
134
|
-
preguntas técnicas de la reunión y las responde sin que nadie las pida: esas
|
|
135
|
-
respuestas llevan `auto: true` en `live/answers.jsonl`. Mientras se responde
|
|
136
|
-
algo, `live/asking.json` dice qué pregunta va (`{question, startedAt, auto}`);
|
|
137
|
-
solo corre una respuesta a la vez y una manual detiene a la automática.
|
|
138
|
-
|
|
139
|
-
## Cambios propuestos a la documentación
|
|
140
|
-
|
|
141
|
-
Si la reunión está ligada a bita, la etapa `proposals` (antes de `wrapup`)
|
|
142
|
-
detecta los cambios explícitos y firmes a páginas que ya existen y los deja en
|
|
143
|
-
la rama `proposal/meeting-<entrada>` de los docs, sin tocar `main`. Ideas,
|
|
144
|
-
dudas y lo que se corrigió después no entran.
|
|
145
|
-
|
|
146
|
-
```sh
|
|
147
|
-
recap proposals ls <id> --json # o --bita-entry <id>
|
|
148
|
-
recap proposals show <id> <n> --json # markdown, citas y diff
|
|
149
|
-
recap proposals accept <id> <n> [--md <archivo editado>] --json
|
|
150
|
-
recap proposals reject <id> <n> --json
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
Acepta o rechaza **solo cuando el usuario lo pida**. Si `accept` deja la
|
|
154
|
-
propuesta en `stale`, la página cambió desde entonces: edítala sobre la versión
|
|
155
|
-
actual y acéptala con `--md`. Cuando no queda ninguna pendiente, recap borra la
|
|
156
|
-
rama. Usa `/recap-proposals` para revisarlas en la sesión.
|
|
36
|
+
el micrófono. Si el contexto no deja claro cuál es, pregunta con una sola línea
|
|
37
|
+
("¿remota o presencial?") antes de arrancar.
|
|
38
|
+
|
|
39
|
+
## Flujo de una reunión
|
|
40
|
+
|
|
41
|
+
1. **Ver el estado**: `recap status --json`. Si ya se está grabando
|
|
42
|
+
(`ALREADY_RECORDING` al arrancar), no arranques otra: avísalo.
|
|
43
|
+
2. **Arrancar.** Si `data.bitaLinked` es true, recap sigue a los cronómetros
|
|
44
|
+
de bita: arranca por bita para que el tiempo también quede medido.
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
bita start "<título>" --kind remote-meeting # o --kind in-person-meeting
|
|
48
|
+
recap start --remote "<título>" # solo si bitaLinked es false
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
3. **Durante la reunión**: `recap ask --active --json` responde la última
|
|
52
|
+
pregunta con las páginas de inkwell y los repos del proyecto. Detalle en
|
|
53
|
+
[live.md](live.md).
|
|
54
|
+
4. **Parar.** Con cronómetro, para el cronómetro y espera; sin él, para recap:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
bita stop <id> --json && recap wait --bita-entry <id> --json
|
|
58
|
+
recap stop --json && recap wait --json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`stop` lanza el procesamiento en segundo plano (transcripción, capturas,
|
|
62
|
+
minuta y cierre). Tarda de uno a cinco minutos por hora de reunión: corre
|
|
63
|
+
`recap wait` con un timeout amplio. El monitor del plugin de Claude Code
|
|
64
|
+
avisa en la sesión cuando termina, así que no hace falta sondear.
|
|
65
|
+
5. **Cierre automático** (con bita e inkwell): recap le pone título y proyecto
|
|
66
|
+
al cronómetro, crea o completa la página en inkwell, pasa pendientes y
|
|
67
|
+
hallazgos al backlog y deja la minuta en la nota de la entrada. El
|
|
68
|
+
resultado viene en `data.wrapup` de `recap wait`; si
|
|
69
|
+
`wrapup.projectResolved` es false, pregunta el proyecto. Detalle y
|
|
70
|
+
correcciones en [wrapup.md](wrapup.md).
|
|
71
|
+
6. **Después**: los cambios que la reunión propuso a la documentación se
|
|
72
|
+
revisan con `/recap-proposals` ([proposals.md](proposals.md)), y el tiempo
|
|
73
|
+
de la reunión llega a Jira con tally, no desde recap.
|
|
74
|
+
|
|
75
|
+
Cambiar el título o el proyecto del cronómetro mientras se graba
|
|
76
|
+
(`bita amend`) no corta la grabación; solo un cambio de `--kind` que cruce la
|
|
77
|
+
línea de reunión la arranca o la detiene. `recap discard` borra la grabación
|
|
78
|
+
activa: solo si el usuario lo pide.
|
|
157
79
|
|
|
158
80
|
## Consultar reuniones
|
|
159
81
|
|
|
@@ -166,17 +88,35 @@ recap show <id> --path
|
|
|
166
88
|
Para responder qué se habló o qué se acordó, lee `summary.md` de las reuniones
|
|
167
89
|
que apliquen. Si hace falta precisión (una cifra, quién dijo qué), ve a
|
|
168
90
|
`transcript.md`, que lleva el minuto de cada párrafo. Cita la reunión y el
|
|
169
|
-
minuto
|
|
170
|
-
|
|
91
|
+
minuto. En remotas, **Sala** es el micrófono local y **Remotos** el audio de la
|
|
92
|
+
llamada; no hay separación por persona.
|
|
171
93
|
|
|
172
94
|
## Regenerar la minuta
|
|
173
95
|
|
|
174
96
|
- Sin intervención: `recap process <id> --from summarize`.
|
|
175
|
-
- Dentro de la sesión, cuando el usuario quiere dirigir el enfoque
|
|
176
|
-
|
|
97
|
+
- Dentro de la sesión, cuando el usuario quiere dirigir el enfoque: `/recap-summarize`.
|
|
98
|
+
- Si una etapa falló, `recap process <id>` retoma desde ahí.
|
|
99
|
+
|
|
100
|
+
## Errores típicos
|
|
101
|
+
|
|
102
|
+
| Código | Causa | Acción |
|
|
103
|
+
|---|---|---|
|
|
104
|
+
| `SCREEN_DENIED` | Recap.app sin permiso de grabación de pantalla | Configuración > Privacidad y seguridad > Grabación de pantalla y audio del sistema |
|
|
105
|
+
| `MICROPHONE_DENIED` | Sin permiso de micrófono | Igual, en Micrófono |
|
|
106
|
+
| `RECORDER_TIMEOUT` | Un diálogo de permisos quedó esperando | `recap setup` |
|
|
107
|
+
| `DEPENDENCY_MISSING`, `MODEL_MISSING` | Falta ffmpeg, whisper-cli, claude o el modelo | `recap setup --install-deps` |
|
|
108
|
+
| `CAPTURE_UNAVAILABLE` | No hay grabador en este equipo | Graba con otra app y usa `recap import <archivo>`; en mac, `recap setup` |
|
|
109
|
+
|
|
110
|
+
## Más detalle, bajo demanda
|
|
111
|
+
|
|
112
|
+
- [wrapup.md](wrapup.md): qué hace el cierre con bita e inkwell, sin inkwell, y cómo corregir el proyecto.
|
|
113
|
+
- [live.md](live.md): transcripción en vivo, `recap ask` y su configuración.
|
|
114
|
+
- [proposals.md](proposals.md): cambios propuestos a la documentación.
|
|
115
|
+
- [storage.md](storage.md): liberar espacio (comprimir, quitar video, borrar).
|
|
177
116
|
|
|
178
117
|
## Lo que no hace
|
|
179
118
|
|
|
180
119
|
- No separa hablantes por persona: los nombres salen del contexto.
|
|
181
120
|
- No sube nada a la nube salvo la transcripción que lee Claude al resumir, al
|
|
182
121
|
responder con `recap ask` y al buscar cambios propuestos.
|
|
122
|
+
- No toca Jira.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# En vivo
|
|
2
|
+
|
|
3
|
+
Mientras se graba, recap transcribe por tramos de 5 a 20 s en
|
|
4
|
+
`live/transcript.jsonl` (una línea `{startMs, endMs, channel, text}`; `mic` es
|
|
5
|
+
Sala y `system` Remotos). Es aproximada: la transcripción de después del stop
|
|
6
|
+
(`transcript.md`) sigue siendo la fuente de verdad.
|
|
7
|
+
|
|
8
|
+
Para responder una pregunta que hicieron en la reunión, con las páginas de
|
|
9
|
+
inkwell y los repos del proyecto (`bita project repo ls`); sin inkwell responde
|
|
10
|
+
solo con los repos:
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
recap ask --active --json # la última pregunta de la transcripción
|
|
14
|
+
recap ask --active --question "¿cómo se despliega X?" --json
|
|
15
|
+
recap ask --meeting <id> --question "..." --json-stream # eventos question/progress/delta/source/done
|
|
16
|
+
recap ask --sources --project <p> --json # qué consultaría, sin llamar a claude
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
La respuesta lleva `found` y `sources` (página, `archivo:línea` o commit) y se
|
|
20
|
+
guarda en `live/answers.jsonl`. Con `found: false` no está documentado: no lo
|
|
21
|
+
completes por tu cuenta.
|
|
22
|
+
|
|
23
|
+
Con `live.autoAsk` (encendido por omisión), el live-worker detecta solo las
|
|
24
|
+
preguntas técnicas de la reunión y las responde sin que nadie las pida: esas
|
|
25
|
+
respuestas llevan `auto: true` en `live/answers.jsonl`. Mientras se responde
|
|
26
|
+
algo, `live/asking.json` dice qué pregunta va (`{question, startedAt, auto}`);
|
|
27
|
+
una respuesta manual detiene a la automática.
|
|
28
|
+
|
|
29
|
+
Se configura con `recap config get|set`: `live.enabled`, `live.openWindow`,
|
|
30
|
+
`live.proposals`, `live.maxChunkSeconds`, `live.assistModel`, `live.autoAsk`,
|
|
31
|
+
`live.autoAskModel`, `live.autoAskMinSeconds` y `live.autoAskConcurrency`.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Cambios propuestos a la documentación
|
|
2
|
+
|
|
3
|
+
Si la reunión está ligada a bita e inkwell está instalado, la etapa `proposals`
|
|
4
|
+
(antes de `wrapup`) detecta los cambios explícitos y firmes a páginas de
|
|
5
|
+
inkwell que ya existen y los deja en la rama `proposal/meeting-<entrada>` de
|
|
6
|
+
sus docs (`inkwell git propose`), sin tocar `main`. Ideas, dudas y lo que se
|
|
7
|
+
corrigió después no entran.
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
recap proposals ls <id> --json # o --bita-entry <id>
|
|
11
|
+
recap proposals show <id> <n> --json # markdown, citas y diff
|
|
12
|
+
recap proposals accept <id> <n> [--md <archivo editado>] --json
|
|
13
|
+
recap proposals reject <id> <n> --json
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Acepta o rechaza **solo cuando el usuario lo pida**. Si `accept` deja la
|
|
17
|
+
propuesta en `stale`, la página cambió desde entonces: edítala sobre la versión
|
|
18
|
+
actual y acéptala con `--md`. Cuando no queda ninguna pendiente, recap borra la
|
|
19
|
+
rama. `/recap-proposals` las revisa una por una en la sesión.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Liberar espacio
|
|
2
|
+
|
|
3
|
+
Solo si el usuario lo pide. Todos aceptan `<id>` o `--bita-entry <id>` y `--json`.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
recap compress-video <id> --preset light|medium|max # recomprime el video en HEVC (solo remotas)
|
|
7
|
+
recap strip-video <id> # quita el video y deja recording.m4a con ambas pistas de audio
|
|
8
|
+
recap prune <id> --intermediates # borra mic.wav, system.wav, transcript-mic/system.json y live/chunks
|
|
9
|
+
recap delete <id> # borra la carpeta completa de la reunión
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`compress-video` y `strip-video` aceptan `--prune-intermediates`. Fallan con
|
|
13
|
+
`NOT_REMOTE` en reuniones presenciales, `NO_VIDEO` si ya no hay video,
|
|
14
|
+
`MEETING_ACTIVE` mientras se graba y `NOT_SMALLER` si la compresión no ahorra
|
|
15
|
+
espacio (el original se conserva). `recap list --json` trae `storage` y
|
|
16
|
+
`hasVideo` de cada reunión.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Cierre de una reunión con bita e inkwell
|
|
2
|
+
|
|
3
|
+
Si `recap status --json` trae `data.bitaLinked: true` (recap está suscrito a
|
|
4
|
+
los eventos de bita desde `recap setup`), las reuniones se arrancan y se paran
|
|
5
|
+
desde bita. recap solo le pide a bita `projects`, `project repo ls`,
|
|
6
|
+
`entries get` y `amend` (título y proyecto).
|
|
7
|
+
|
|
8
|
+
Al parar el cronómetro, recap hace todo lo demás sin que nadie lo pida:
|
|
9
|
+
|
|
10
|
+
- transcribe y escribe la minuta;
|
|
11
|
+
- le pone al cronómetro un título real, si el que tenía era genérico (`bita amend`);
|
|
12
|
+
- le asigna el proyecto si no tenía y la conversación lo deja claro (`bita amend`);
|
|
13
|
+
- crea la página en inkwell, ligada a la entrada (`inkwell page new --from-entry`),
|
|
14
|
+
o agrega una sección a la que ya tenía (`inkwell page ls --entry`), y la escribe;
|
|
15
|
+
- pasa pendientes y hallazgos al backlog de inkwell (`inkwell backlog add`);
|
|
16
|
+
- deja la minuta en la sección «Reunión» de la nota de la entrada
|
|
17
|
+
(`inkwell note save <entrada> --section Reunión --md …`).
|
|
18
|
+
|
|
19
|
+
El resultado está en `data.wrapup` de `recap wait`: `title`, `project`,
|
|
20
|
+
`projectResolved`, `pageId`, `pageCreated` y `backlogKeys`.
|
|
21
|
+
|
|
22
|
+
## Corregir el proyecto
|
|
23
|
+
|
|
24
|
+
Si `wrapup.projectResolved` es false, pregunta solo «¿De qué proyecto fue?» y,
|
|
25
|
+
con la respuesta:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
bita amend <entryId> --project <X>
|
|
29
|
+
inkwell page move <pageId> --project <X>
|
|
30
|
+
inkwell backlog edit <CLAVE> --project <X> # una por cada valor de wrapup.backlogKeys
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Sin inkwell, o con un inkwell viejo
|
|
34
|
+
|
|
35
|
+
La reunión igual queda procesada: las etapas `proposals` y `wrapup` quedan en
|
|
36
|
+
`skipped` con el motivo en `stages.<etapa>.reason` y la pista
|
|
37
|
+
`npm i -g @kikedealba/inkwell && inkwell setup`; la minuta se queda en
|
|
38
|
+
`summary.md` de la carpeta de la reunión. Si inkwell no tiene la capacidad
|
|
39
|
+
`docs.entry-notes`, se escriben la página y el backlog, pero la minuta no pasa
|
|
40
|
+
a la nota (queda anotado en `process.log`). Después de instalar o actualizar
|
|
41
|
+
inkwell, `recap process <id> --from proposals` lo completa.
|
|
42
|
+
|
|
43
|
+
## Qué responder al usuario
|
|
44
|
+
|
|
45
|
+
- Título y duración.
|
|
46
|
+
- Con bita e inkwell: el proyecto, la página (`wrapup.pageId`) y cuántos
|
|
47
|
+
pendientes y hallazgos quedaron en el backlog.
|
|
48
|
+
- Sin bita o sin inkwell: los **Acuerdos** y **Pendientes** de la minuta, tal cual.
|
|
49
|
+
- Si una etapa falló, su error y la sugerencia `recap process <id>`.
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
+
name: recap-ask
|
|
2
3
|
description: Responde la última pregunta de la reunión en curso con las páginas y repos del proyecto
|
|
3
4
|
argument-hint: [pregunta, opcional]
|
|
4
5
|
allowed-tools: Bash(recap ask:*)
|
|
6
|
+
disable-model-invocation: true
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
Responde en vivo una pregunta de la reunión que se está grabando.
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
+
name: recap-list
|
|
2
3
|
description: Lista las reuniones grabadas, o muestra la minuta de una
|
|
3
4
|
argument-hint: [id, parte del título o "last"]
|
|
4
5
|
allowed-tools: Bash(recap list:*), Bash(recap show:*)
|
|
6
|
+
disable-model-invocation: true
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
**Sin `$ARGUMENTS`**, lista las reuniones recientes:
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
---
|
|
2
|
+
name: recap-proposals
|
|
2
3
|
description: Revisa los cambios a la documentación que propuso una reunión
|
|
3
4
|
argument-hint: [id de la reunión o "last"]
|
|
4
5
|
allowed-tools: Bash(recap proposals:*), Bash(recap show:*), Read, Write
|
|
6
|
+
disable-model-invocation: true
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
Al cerrar una reunión ligada a bita, recap deja los cambios explícitos a
|
|
8
|
-
páginas existentes como propuestas en la rama
|
|
9
|
-
|
|
10
|
+
páginas existentes de inkwell como propuestas en la rama
|
|
11
|
+
`proposal/meeting-<entrada>` de sus docs. Nada llega a `main` sin aceptarse.
|
|
12
|
+
Aceptar o rechazar necesita inkwell instalado (`npm i -g @kikedealba/inkwell &&
|
|
13
|
+
inkwell setup`).
|
|
10
14
|
|
|
11
15
|
1. La reunión es `$ARGUMENTS`, o `last` si viene vacío. Lista sus propuestas:
|
|
12
16
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
+
name: recap-start
|
|
2
3
|
description: Empieza a grabar una reunión (remota o presencial)
|
|
3
4
|
argument-hint: [remota|presencial] [título]
|
|
4
5
|
allowed-tools: Bash(recap start:*), Bash(recap status:*), Bash(recap import:*), Bash(bita start:*)
|
|
6
|
+
disable-model-invocation: true
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
Estado actual:
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: recap-stop
|
|
3
|
+
description: Termina la grabación y deja la reunión documentada
|
|
4
|
+
argument-hint: [--no-wait para no esperar el resultado]
|
|
5
|
+
allowed-tools: Bash(recap stop:*), Bash(recap status:*), Bash(recap wait:*), Bash(recap show:*), Bash(bita stop:*), Bash(bita ls:*), Bash(bita amend:*), Bash(inkwell page move:*), Bash(inkwell backlog edit:*)
|
|
6
|
+
disable-model-invocation: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Detén la grabación activa y deja la reunión documentada.
|
|
10
|
+
|
|
11
|
+
Grabación actual:
|
|
12
|
+
|
|
13
|
+
!`recap status --json`
|
|
14
|
+
|
|
15
|
+
Si no hay grabación activa (`NOT_RECORDING`), dilo en una línea y termina.
|
|
16
|
+
|
|
17
|
+
## Si la grabación sigue a un cronómetro de bita
|
|
18
|
+
|
|
19
|
+
Cuando `data.active.bitaEntryId` trae un id, para **el cronómetro**, no recap,
|
|
20
|
+
sin escribir la página:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
bita stop <id> --json
|
|
24
|
+
recap wait --bita-entry <id> --json
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
El evento de bita detiene la grabación y recap hace lo demás: transcribe,
|
|
28
|
+
escribe la minuta, le pone título y proyecto al cronómetro (`bita amend`),
|
|
29
|
+
crea o completa la página en inkwell, pasa pendientes y hallazgos al backlog
|
|
30
|
+
de inkwell y deja la minuta en la nota de la entrada.
|
|
31
|
+
|
|
32
|
+
Sin inkwell, las etapas `proposals` y `wrapup` quedan en `skipped` con su
|
|
33
|
+
motivo (`stages.wrapup.reason`) y la minuta se queda en la carpeta de la
|
|
34
|
+
reunión; sugiere `npm i -g @kikedealba/inkwell && inkwell setup` y después
|
|
35
|
+
`recap process <id> --from proposals`.
|
|
36
|
+
|
|
37
|
+
`recap wait` tarda de uno a cinco minutos en una reunión de una hora: córrelo con
|
|
38
|
+
un timeout amplio (15 min). Si después de un minuto `recap status` sigue
|
|
39
|
+
grabando, el evento no llegó: párala con `recap stop`.
|
|
40
|
+
|
|
41
|
+
## Si es una grabación suelta
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
recap stop --json
|
|
45
|
+
recap wait --json
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Qué responder
|
|
49
|
+
|
|
50
|
+
Con el resultado de `recap wait` responde:
|
|
51
|
+
|
|
52
|
+
- título y duración;
|
|
53
|
+
- con bita e inkwell: el proyecto, la página (`wrapup.pageId`) y cuántos
|
|
54
|
+
pendientes y hallazgos quedaron en el backlog;
|
|
55
|
+
- sin bita o sin inkwell: los **Acuerdos** y **Pendientes** de la minuta, tal cual.
|
|
56
|
+
|
|
57
|
+
Si una etapa falló, muestra su error y sugiere `recap process <id>`: retoma
|
|
58
|
+
desde la etapa que falló.
|
|
59
|
+
|
|
60
|
+
**Si `wrapup.projectResolved` es false**, pregunta solo «¿De qué proyecto fue?»
|
|
61
|
+
y, con la respuesta:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
bita amend <entryId> --project <X>
|
|
65
|
+
inkwell page move <pageId> --project <X>
|
|
66
|
+
inkwell backlog edit <CLAVE> --project <X> # una por cada valor de wrapup.backlogKeys
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
El tiempo de la reunión se vuelca a Jira después con tally, no desde aquí.
|
|
70
|
+
|
|
71
|
+
Con `--no-wait` en `$ARGUMENTS`, solo para y responde en una línea que el
|
|
72
|
+
procesamiento sigue en segundo plano. El monitor del plugin avisa en la sesión
|
|
73
|
+
cuando la reunión termine de procesarse.
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
+
name: recap-summarize
|
|
2
3
|
description: Rehace la minuta de una reunión dentro de la sesión, con indicaciones
|
|
3
4
|
argument-hint: [id o "last"] [indicaciones, p. ej. "enfócate en los riesgos"]
|
|
4
5
|
allowed-tools: Bash(recap prompt:*), Bash(recap save-summary:*), Bash(recap show:*), Read, Write
|
|
6
|
+
disable-model-invocation: true
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
Rehaz la minuta de una reunión aquí mismo, en lugar del `claude -p` sin
|