@kikedealba/recap 0.10.0 → 0.11.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.
- package/README.md +44 -18
- package/dist/cli/commands/watch.js +109 -0
- package/dist/cli/router.js +3 -0
- package/dist/setup/integration.js +24 -29
- package/package.json +2 -3
- package/skills/recap/SKILL.md +78 -160
- 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} +3 -1
- package/{commands/recap-list.md → skills/recap-list/SKILL.md} +2 -0
- package/{commands/recap-proposals.md → skills/recap-proposals/SKILL.md} +3 -1
- 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/{commands/recap-stop.md → skills/recap-stop/SKILL.md} +8 -8
- package/{commands/recap-summarize.md → skills/recap-summarize/SKILL.md} +3 -1
package/README.md
CHANGED
|
@@ -37,9 +37,14 @@ Requisitos: Node 24 o superior, ffmpeg, whisper.cpp (`whisper-cli`) y
|
|
|
37
37
|
`start`, `stop`, `cancel` y `amend` de las entradas `remote-meeting` e
|
|
38
38
|
`in-person-meeting`. Reemplaza al viejo `bita hooks add` y quita ese hook si
|
|
39
39
|
lo encuentra, para que no se dispare dos veces;
|
|
40
|
-
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
- en Claude Code agrega o actualiza el marketplace `KikeDeAlba/recap` e instala
|
|
41
|
+
o actualiza el plugin `recap@recap` (`claude plugin marketplace add|update` y
|
|
42
|
+
`claude plugin install|update --scope user`), así el plugin queda en la misma
|
|
43
|
+
versión que la CLI; también quita los archivos sueltos que versiones viejas
|
|
44
|
+
dejaron en `~/.claude`;
|
|
45
|
+
- en opencode, Codex y Gemini CLI instala la skill y las skills de usuario en el
|
|
46
|
+
formato de cada uno (`--agents codex,gemini`, `--agents all` o
|
|
47
|
+
`--agents none`).
|
|
43
48
|
|
|
44
49
|
En Windows y Linux `recap start` falla con `CAPTURE_UNAVAILABLE`: graba con la
|
|
45
50
|
app que quieras y procesa el archivo con
|
|
@@ -133,26 +138,47 @@ recap prompt <meeting> # print the summary prompt with transcrip
|
|
|
133
138
|
recap save-summary <meeting> file.md # store minutes written elsewhere
|
|
134
139
|
```
|
|
135
140
|
|
|
136
|
-
## Claude Code
|
|
141
|
+
## Plugin de Claude Code
|
|
137
142
|
|
|
138
|
-
|
|
143
|
+
El repositorio también es un marketplace de plugins de Claude Code. `recap setup`
|
|
144
|
+
lo instala y lo mantiene al día; a mano sería:
|
|
139
145
|
|
|
140
146
|
```
|
|
141
|
-
|
|
142
|
-
|
|
147
|
+
claude plugin marketplace add KikeDeAlba/recap
|
|
148
|
+
claude plugin install recap@recap --scope user
|
|
149
|
+
claude plugin marketplace update recap && claude plugin update recap@recap # al actualizar la CLI
|
|
143
150
|
```
|
|
144
151
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
Trae tres cosas:
|
|
153
|
+
|
|
154
|
+
- **La skill `recap`**, que Claude carga sola cuando la conversación trata de
|
|
155
|
+
reuniones ("¿qué acordamos en la reunión de ayer?"). Es la única fuente del
|
|
156
|
+
flujo de una reunión; bita y tally enlazan a ella. Lo largo (cierre con bita e
|
|
157
|
+
inkwell, en vivo, propuestas, espacio) vive en archivos aparte que se leen
|
|
158
|
+
solo cuando hacen falta.
|
|
159
|
+
- **Skills de usuario** con `disable-model-invocation: true`: no ocupan contexto
|
|
160
|
+
y solo corren cuando las escribes.
|
|
161
|
+
|
|
162
|
+
| Skill | Qué hace |
|
|
163
|
+
|---|---|
|
|
164
|
+
| `/recap:recap-start [remota\|presencial] [título]` | Empieza a grabar; saca el modo de los argumentos o de la conversación y pregunta si no puede |
|
|
165
|
+
| `/recap:recap-stop [--no-wait]` | Para la grabación (por bita si la sigue un cronómetro), espera el procesamiento y muestra el resultado |
|
|
166
|
+
| `/recap:recap-status` | Dice si se está grabando y en qué va el procesamiento |
|
|
167
|
+
| `/recap:recap-list [reunión]` | Lista las reuniones o muestra la minuta de una |
|
|
168
|
+
| `/recap:recap-summarize [reunión] [indicaciones]` | Rehace la minuta dentro de la sesión y la guarda con `recap save-summary` |
|
|
169
|
+
| `/recap:recap-ask [pregunta]` | Responde la última pregunta de la reunión en curso, o la que le pases, con las páginas de inkwell y los repos del proyecto |
|
|
170
|
+
| `/recap:recap-proposals [reunión]` | Revisa los cambios a la documentación que propuso una reunión |
|
|
171
|
+
|
|
172
|
+
- **Un monitor** (`monitors/monitors.json`) que corre `recap watch` en segundo
|
|
173
|
+
plano en cada sesión interactiva. Revisa las carpetas de reuniones cada 5 s,
|
|
174
|
+
sin llamar al modelo, y escribe una sola línea cuando una reunión termina de
|
|
175
|
+
procesarse o falla; esa línea le llega a Claude como notificación. No corre
|
|
176
|
+
con `claude -p`. Si `recap` no está en el `PATH`, no hace nada. Para apagarlo,
|
|
177
|
+
define `RECAP_MONITOR=off` en el entorno de Claude Code (por ejemplo en
|
|
178
|
+
`"env"` de `~/.claude/settings.json`).
|
|
179
|
+
|
|
180
|
+
Las skills llaman a `recap`, así que tiene que estar en el `PATH` del shell que
|
|
181
|
+
usa Claude Code.
|
|
156
182
|
|
|
157
183
|
## Live assistant
|
|
158
184
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { readdirSync, statSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { loadConfig, rootDir } from "../../core/config.js";
|
|
4
|
+
import { MEETING_FILE, loadMeeting } from "../../core/meeting.js";
|
|
5
|
+
import { sleep } from "../../core/proc.js";
|
|
6
|
+
import { suffix, trimmed } from "../../core/text.js";
|
|
7
|
+
import { usageError } from "../../errors.js";
|
|
8
|
+
import { parseArgs } from "../args.js";
|
|
9
|
+
import { output } from "../output.js";
|
|
10
|
+
import { failedStage, isSettled } from "./query.js";
|
|
11
|
+
export const WATCH_OPT_OUT = 'RECAP_MONITOR';
|
|
12
|
+
const NOTICE = ' (FYI: act on it only if this session is handling that meeting)';
|
|
13
|
+
export function watchDisabled(env = process.env) {
|
|
14
|
+
const value = trimmed(env[WATCH_OPT_OUT] ?? '').toLowerCase();
|
|
15
|
+
return ['0', 'off', 'false', 'no'].includes(value);
|
|
16
|
+
}
|
|
17
|
+
export function describeSettled(meeting, dir) {
|
|
18
|
+
const failed = failedStage(meeting);
|
|
19
|
+
const base = { id: meeting.id, title: meeting.title, status: meeting.status, dir };
|
|
20
|
+
if (meeting.status !== 'processed') {
|
|
21
|
+
const where = failed ? ` at ${failed[0]}` : '';
|
|
22
|
+
const reason = suffix(trimmed((failed ? failed[1].error : meeting.error) ?? 'no reason given').replace(/\s+/g, ' '), 200);
|
|
23
|
+
return { ...base, failed: true, message: `recap: meeting "${meeting.title}" failed${where}: ${reason} (${meeting.id}); run \`recap process ${meeting.id}\` to resume${NOTICE}` };
|
|
24
|
+
}
|
|
25
|
+
const parts = [`recap: meeting "${meeting.title}" finished processing (${meeting.id})`, `minutes at ${path.join(dir, 'summary.md')}`];
|
|
26
|
+
const wrapup = meeting.wrapup;
|
|
27
|
+
if (wrapup?.pageId !== undefined)
|
|
28
|
+
parts.push(`inkwell page #${wrapup.pageId}`);
|
|
29
|
+
if (wrapup && !wrapup.projectResolved)
|
|
30
|
+
parts.push('project unresolved');
|
|
31
|
+
return { ...base, failed: false, message: `${parts.join('; ')}${NOTICE}` };
|
|
32
|
+
}
|
|
33
|
+
export class MeetingWatcher {
|
|
34
|
+
root;
|
|
35
|
+
seen = new Map();
|
|
36
|
+
primed = false;
|
|
37
|
+
constructor(root) {
|
|
38
|
+
this.root = root;
|
|
39
|
+
}
|
|
40
|
+
tick() {
|
|
41
|
+
let names;
|
|
42
|
+
try {
|
|
43
|
+
names = readdirSync(this.root);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
names = [];
|
|
47
|
+
}
|
|
48
|
+
const events = [];
|
|
49
|
+
const present = new Set();
|
|
50
|
+
for (const name of names) {
|
|
51
|
+
const dir = path.join(this.root, name);
|
|
52
|
+
let mtimeMs;
|
|
53
|
+
try {
|
|
54
|
+
mtimeMs = statSync(path.join(dir, MEETING_FILE)).mtimeMs;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
present.add(name);
|
|
60
|
+
const before = this.seen.get(name);
|
|
61
|
+
if (before && before.mtimeMs === mtimeMs)
|
|
62
|
+
continue;
|
|
63
|
+
let meeting;
|
|
64
|
+
try {
|
|
65
|
+
meeting = loadMeeting(dir);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const settled = isSettled(meeting);
|
|
71
|
+
this.seen.set(name, { mtimeMs, settled });
|
|
72
|
+
const wasSettled = before ? before.settled : !this.primed;
|
|
73
|
+
if (settled && !wasSettled)
|
|
74
|
+
events.push(describeSettled(meeting, dir));
|
|
75
|
+
}
|
|
76
|
+
for (const name of [...this.seen.keys()])
|
|
77
|
+
if (!present.has(name))
|
|
78
|
+
this.seen.delete(name);
|
|
79
|
+
this.primed = true;
|
|
80
|
+
return events;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export async function watchCommand(argv) {
|
|
84
|
+
const json = argv.includes('--json');
|
|
85
|
+
let interval;
|
|
86
|
+
let root;
|
|
87
|
+
try {
|
|
88
|
+
const args = parseArgs(argv, { values: ['interval'], maxPositionals: 0 });
|
|
89
|
+
interval = args.number('interval') ?? 5;
|
|
90
|
+
if (interval < 1 || interval > 300)
|
|
91
|
+
throw usageError('--interval takes seconds between 1 and 300');
|
|
92
|
+
root = rootDir(loadConfig());
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
return output('watch', json, () => {
|
|
96
|
+
throw error;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (watchDisabled())
|
|
100
|
+
return 0;
|
|
101
|
+
process.stdout.on('error', () => process.exit(0));
|
|
102
|
+
const watcher = new MeetingWatcher(root);
|
|
103
|
+
watcher.tick();
|
|
104
|
+
for (;;) {
|
|
105
|
+
await sleep(interval * 1000);
|
|
106
|
+
for (const event of watcher.tick())
|
|
107
|
+
process.stdout.write(`${json ? JSON.stringify(event) : event.message}\n`);
|
|
108
|
+
}
|
|
109
|
+
}
|
package/dist/cli/router.js
CHANGED
|
@@ -12,6 +12,7 @@ import { proposalsCommand } from "./commands/proposals.js";
|
|
|
12
12
|
import { listCommand, processCommand, promptCommand, saveSummaryCommand, showCommand, waitCommand } from "./commands/query.js";
|
|
13
13
|
import { discardCommand, importCommand, startCommand, statusCommand, stopCommand } from "./commands/recording.js";
|
|
14
14
|
import { setupCommand } from "./commands/setup.js";
|
|
15
|
+
import { watchCommand } from "./commands/watch.js";
|
|
15
16
|
import { output } from "./output.js";
|
|
16
17
|
async function capabilitiesCommand(argv) {
|
|
17
18
|
return output('capabilities', argv.includes('--json'), async () => {
|
|
@@ -42,6 +43,7 @@ const COMMANDS = {
|
|
|
42
43
|
ask: askCommand,
|
|
43
44
|
proposals: proposalsCommand,
|
|
44
45
|
config: configCommand,
|
|
46
|
+
watch: watchCommand,
|
|
45
47
|
'live-worker': liveWorkerCommand,
|
|
46
48
|
capabilities: capabilitiesCommand,
|
|
47
49
|
};
|
|
@@ -64,6 +66,7 @@ export function help() {
|
|
|
64
66
|
' recap proposals ls|show|accept|reject <meeting> [n] [--bita-entry id] [--md file]',
|
|
65
67
|
' recap compress-video <meeting> --preset light|medium|max | strip-video <meeting> | prune <meeting> --intermediates | delete <meeting>',
|
|
66
68
|
' recap config get [key] | config set <key> <value>',
|
|
69
|
+
' recap watch [--interval s]: one line per meeting that finishes processing; RECAP_MONITOR=off turns it off',
|
|
67
70
|
' recap setup [--install-deps] [--skip-models] [--skip-permissions] [--skip-bita] [--skip-app] [--agents detected|all|none|claude,opencode,codex,gemini]',
|
|
68
71
|
' recap capabilities',
|
|
69
72
|
'',
|
|
@@ -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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kikedealba/recap",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
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",
|
|
@@ -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
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: recap
|
|
3
|
-
description: Graba reuniones con la CLI
|
|
3
|
+
description: Graba reuniones con la CLI recap y las vuelve minuta con acuerdos y pendientes. Frases como "graba la reunión", "ya terminó la reunión", "¿se está grabando?", "¿qué acordamos en la reunión de ayer?".
|
|
4
4
|
---
|
|
5
5
|
|
|
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,154 +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 e inkwell
|
|
78
|
-
|
|
79
|
-
Cada herramienta hace una sola cosa:
|
|
80
|
-
|
|
81
|
-
- **bita** lleva el tiempo (cronómetros). recap solo le pide `projects`,
|
|
82
|
-
`project repo ls`, `entries get` y `amend` (título y proyecto).
|
|
83
|
-
- **inkwell** guarda la documentación: páginas, backlog, propuestas, historial
|
|
84
|
-
y la nota de cada entrada de bita (`inkwell note …`).
|
|
85
|
-
- **tally** vuelca a Jira el tiempo de bita (`tally summary --pending`); recap
|
|
86
|
-
no toca Jira.
|
|
87
|
-
|
|
88
|
-
Si `recap status --json` trae `data.bitaLinked: true` (recap está suscrito a
|
|
89
|
-
los eventos de bita desde `recap setup`), **arranca y para las reuniones desde
|
|
90
|
-
bita**, no desde recap: así el tiempo queda medido y la grabación sigue al
|
|
91
|
-
cronómetro.
|
|
92
|
-
|
|
93
|
-
```sh
|
|
94
|
-
bita start "<título>" --kind remote-meeting
|
|
95
|
-
bita start "<título>" --kind in-person-meeting
|
|
96
|
-
bita stop <id> --json # sin escribir la página: eso lo hace recap
|
|
97
|
-
recap wait --bita-entry <id> --json # espera a que todo quede listo
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
Cambiar el título o el proyecto del cronómetro mientras se graba (`bita amend`)
|
|
101
|
-
no corta ni duplica la grabación: recap solo actualiza los datos de la reunión.
|
|
102
|
-
Solo un cambio de tipo (`--kind`) que cruce la línea de reunión la arranca o la
|
|
103
|
-
detiene.
|
|
104
|
-
|
|
105
|
-
Al parar, recap hace todo lo demás sin que nadie lo pida:
|
|
106
|
-
|
|
107
|
-
- transcribe y escribe la minuta;
|
|
108
|
-
- le pone al cronómetro un título real, si el que tenía era genérico (`bita amend`);
|
|
109
|
-
- le asigna el proyecto si no tenía y la conversación lo deja claro (`bita amend`);
|
|
110
|
-
- crea la página en inkwell, ligada a la entrada (`inkwell page new --from-entry`),
|
|
111
|
-
o agrega una sección a la que ya tenía (`inkwell page ls --entry`), y la escribe;
|
|
112
|
-
- pasa pendientes y hallazgos al backlog de inkwell (`inkwell backlog add`);
|
|
113
|
-
- deja la minuta en la sección «Reunión» de la nota de la entrada
|
|
114
|
-
(`inkwell note save <entrada> --section Reunión --md …`).
|
|
115
|
-
|
|
116
|
-
El resultado está en `data.wrapup` de `recap wait`. Si `wrapup.projectResolved`
|
|
117
|
-
es false, pregunta el proyecto, aplícalo con `bita amend <id> --project …` y
|
|
118
|
-
mueve la página y el backlog con `inkwell page move --project` e
|
|
119
|
-
`inkwell backlog edit --project`.
|
|
120
|
-
|
|
121
|
-
**Sin inkwell** la reunión igual queda procesada: las etapas `proposals` y
|
|
122
|
-
`wrapup` quedan en `skipped` con el motivo en `stages.<etapa>.reason` y la pista
|
|
123
|
-
`npm i -g @kikedealba/inkwell && inkwell setup`; la minuta se queda en
|
|
124
|
-
`summary.md` de la carpeta de la reunión. Si inkwell es viejo y no tiene la
|
|
125
|
-
capacidad `docs.entry-notes`, se escribe la página y el backlog pero la minuta
|
|
126
|
-
no pasa a la nota (queda anotado en `process.log`). Después de instalar o
|
|
127
|
-
actualizar inkwell, `recap process <id> --from proposals` lo completa.
|
|
128
|
-
|
|
129
|
-
## En vivo
|
|
130
|
-
|
|
131
|
-
Mientras se graba, recap transcribe por tramos de 5 a 20 s en
|
|
132
|
-
`live/transcript.jsonl` (una línea `{startMs, endMs, channel, text}`; `mic` es
|
|
133
|
-
Sala y `system` Remotos). Es aproximada: la transcripción de después del stop
|
|
134
|
-
(`transcript.md`) sigue siendo la fuente de verdad.
|
|
135
|
-
|
|
136
|
-
Para responder una pregunta que hicieron en la reunión, con las páginas de
|
|
137
|
-
inkwell y los repos del proyecto (`bita project repo ls`); sin inkwell responde
|
|
138
|
-
solo con los repos:
|
|
139
|
-
|
|
140
|
-
```sh
|
|
141
|
-
recap ask --active --json # la última pregunta de la transcripción
|
|
142
|
-
recap ask --active --question "¿cómo se despliega X?" --json
|
|
143
|
-
recap ask --meeting <id> --question "..." --json-stream # eventos question/progress/delta/source/done
|
|
144
|
-
recap ask --sources --project <p> --json # qué consultaría, sin llamar a claude
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
La respuesta lleva `found` y `sources` (página, `archivo:línea` o commit) y se
|
|
148
|
-
guarda en `live/answers.jsonl`. Con `found: false` no está documentado: no lo
|
|
149
|
-
completes por tu cuenta. Se configura con `recap config get|set`
|
|
150
|
-
(`live.enabled`, `live.openWindow`, `live.proposals`, `live.maxChunkSeconds`,
|
|
151
|
-
`live.assistModel`, `live.autoAsk`, `live.autoAskModel`,
|
|
152
|
-
`live.autoAskMinSeconds`).
|
|
153
|
-
|
|
154
|
-
Con `live.autoAsk` (encendido por omisión), el live-worker detecta solo las
|
|
155
|
-
preguntas técnicas de la reunión y las responde sin que nadie las pida: esas
|
|
156
|
-
respuestas llevan `auto: true` en `live/answers.jsonl`. Mientras se responde
|
|
157
|
-
algo, `live/asking.json` dice qué pregunta va (`{question, startedAt, auto}`);
|
|
158
|
-
solo corre una respuesta a la vez y una manual detiene a la automática.
|
|
159
|
-
|
|
160
|
-
## Cambios propuestos a la documentación
|
|
161
|
-
|
|
162
|
-
Si la reunión está ligada a bita e inkwell está instalado, la etapa `proposals`
|
|
163
|
-
(antes de `wrapup`) detecta los cambios explícitos y firmes a páginas de inkwell
|
|
164
|
-
que ya existen y los deja en la rama `proposal/meeting-<entrada>` de sus docs
|
|
165
|
-
(`inkwell git propose`), sin tocar `main`. Ideas,
|
|
166
|
-
dudas y lo que se corrigió después no entran.
|
|
167
|
-
|
|
168
|
-
```sh
|
|
169
|
-
recap proposals ls <id> --json # o --bita-entry <id>
|
|
170
|
-
recap proposals show <id> <n> --json # markdown, citas y diff
|
|
171
|
-
recap proposals accept <id> <n> [--md <archivo editado>] --json
|
|
172
|
-
recap proposals reject <id> <n> --json
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
Acepta o rechaza **solo cuando el usuario lo pida**. Si `accept` deja la
|
|
176
|
-
propuesta en `stale`, la página cambió desde entonces: edítala sobre la versión
|
|
177
|
-
actual y acéptala con `--md`. Cuando no queda ninguna pendiente, recap borra la
|
|
178
|
-
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.
|
|
179
79
|
|
|
180
80
|
## Consultar reuniones
|
|
181
81
|
|
|
@@ -188,17 +88,35 @@ recap show <id> --path
|
|
|
188
88
|
Para responder qué se habló o qué se acordó, lee `summary.md` de las reuniones
|
|
189
89
|
que apliquen. Si hace falta precisión (una cifra, quién dijo qué), ve a
|
|
190
90
|
`transcript.md`, que lleva el minuto de cada párrafo. Cita la reunión y el
|
|
191
|
-
minuto
|
|
192
|
-
|
|
91
|
+
minuto. En remotas, **Sala** es el micrófono local y **Remotos** el audio de la
|
|
92
|
+
llamada; no hay separación por persona.
|
|
193
93
|
|
|
194
94
|
## Regenerar la minuta
|
|
195
95
|
|
|
196
96
|
- Sin intervención: `recap process <id> --from summarize`.
|
|
197
|
-
- Dentro de la sesión, cuando el usuario quiere dirigir el enfoque
|
|
198
|
-
|
|
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).
|
|
199
116
|
|
|
200
117
|
## Lo que no hace
|
|
201
118
|
|
|
202
119
|
- No separa hablantes por persona: los nombres salen del contexto.
|
|
203
120
|
- No sube nada a la nube salvo la transcripción que lee Claude al resumir, al
|
|
204
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
|
-
|
|
2
|
+
name: recap-ask
|
|
3
|
+
description: Responde la última pregunta de la reunión en curso
|
|
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,7 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
2
|
+
name: recap-proposals
|
|
3
|
+
description: Revisa los cambios de 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
|
|
@@ -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:
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
+
name: recap-stop
|
|
2
3
|
description: Termina la grabación y deja la reunión documentada
|
|
3
4
|
argument-hint: [--no-wait para no esperar el resultado]
|
|
4
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
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
Detén la grabación activa y deja la reunión documentada.
|
|
@@ -22,13 +24,10 @@ bita stop <id> --json
|
|
|
22
24
|
recap wait --bita-entry <id> --json
|
|
23
25
|
```
|
|
24
26
|
|
|
25
|
-
El evento de bita detiene la grabación y recap hace lo demás:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
- crea o completa la página en inkwell;
|
|
30
|
-
- pasa los pendientes y hallazgos al backlog de inkwell;
|
|
31
|
-
- deja la minuta en la sección «Reunión» de la nota de la entrada (`inkwell note save`).
|
|
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.
|
|
32
31
|
|
|
33
32
|
Sin inkwell, las etapas `proposals` y `wrapup` quedan en `skipped` con su
|
|
34
33
|
motivo (`stages.wrapup.reason`) y la minuta se queda en la carpeta de la
|
|
@@ -70,4 +69,5 @@ inkwell backlog edit <CLAVE> --project <X> # una por cada valor de wrapup.back
|
|
|
70
69
|
El tiempo de la reunión se vuelca a Jira después con tally, no desde aquí.
|
|
71
70
|
|
|
72
71
|
Con `--no-wait` en `$ARGUMENTS`, solo para y responde en una línea que el
|
|
73
|
-
procesamiento sigue en segundo plano.
|
|
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
|
-
|
|
2
|
+
name: recap-summarize
|
|
3
|
+
description: Rehace la minuta de una reunió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
|