@memoring/cli 0.12.1 → 0.13.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 +2 -0
- package/dist/commands/inbox.js +3 -1
- package/dist/commands/stage.js +64 -1
- package/dist/main.js +1 -1
- package/package.json +1 -1
- package/skills/memoring-cli/SKILL.md +2 -1
package/README.md
CHANGED
|
@@ -87,12 +87,14 @@ Cada item do lote (1 a 50, all-or-nothing):
|
|
|
87
87
|
"front": "Quais são os quatro objetivos fundamentais da República (art. 3º da CF/88)?",
|
|
88
88
|
"back": "I — construir uma sociedade livre, justa e solidária; II — garantir o desenvolvimento nacional; III — erradicar a pobreza e reduzir as desigualdades; IV — promover o bem de todos.",
|
|
89
89
|
"subjectName": "Direito Constitucional",
|
|
90
|
+
"conceptKey": "const-cf88-art-3",
|
|
90
91
|
"tags": ["cf88", "art-3"],
|
|
91
92
|
"source": "Apostila constitucional.pdf"
|
|
92
93
|
}
|
|
93
94
|
```
|
|
94
95
|
|
|
95
96
|
- `type`: `NOTE` (nota, exige `content` em markdown; `NORMAL` legado é aceito e mapeado para `NOTE`), `FLASHCARD` ou `ONE_SHOT` (exigem `front` + `back`), `QUESTION` (exige `question`: `kind` `MULTIPLA_ESCOLHA`/`CERTO_ERRADO`, `statementHtml`, `correctAlternative` 1-based — 1=Certo/2=Errado —, `alternatives` 2–5 só em múltipla escolha, `commentHtml`).
|
|
97
|
+
- `conceptKey`: conceito do item em slug minúsculo (letras, números e hífens, até 80 chars). Opcional por compatibilidade, mas **fortemente recomendado em FLASHCARD/ONE_SHOT/QUESTION** — cartões sobre o MESMO conceito compartilham a MESMA chave e conceitos DIFERENTES usam chaves diferentes (nunca reuse a chave). Ex.: um flashcard e uma questão sobre o art. 4º do CTN usam ambos `"trib-art-4"`. No app, o whiteboard do Rascunho agrupa por conceito: ângulos do mesmo conceito contam como uma frente só nas rodadas guiadas; sem chave, cada cartão é uma frente individual. No `inbox update <id>`, o `conceptKey` atual é preservado quando o campo não é informado.
|
|
96
98
|
- `deckName`: **obrigatório** (ou `--deck` no create) — cartão não fica sem baralho; o nome de um baralho existente (`memoring deck list`) é reutilizado, nome novo vira baralho criado no envio.
|
|
97
99
|
- `source`: origem do material — default `"Importação assistida (CLI)"`.
|
|
98
100
|
- Limites por tipo são **tetos, nunca cotas**: `memoring stage caps` mostra/grava sua preferência (`livre`/`-1` = sem teto preferencial — o padrão, não um incentivo a inflar o lote; `0` = não gerar o tipo) — o `stage schema` a expõe ao agente (`userCaps`) e o `create` a impõe; flags `--max-*` no `create` vencem por lote. O 50 é apenas o limite técnico por requisição, não a meta: sem quantidade explícita, o agente deve selecionar apenas os pontos realmente cobráveis e manter uma carga de revisão sustentável.
|
package/dist/commands/inbox.js
CHANGED
|
@@ -60,6 +60,7 @@ async function updateInboxItem(parsed, id) {
|
|
|
60
60
|
subtopicName: overrides.subtopicName ?? stringFlag(flags, 'subtopic') ?? current.subtopicName ?? null,
|
|
61
61
|
tags: overrides.tags ?? (tagsFlag !== undefined ? parseTagsFlag(tagsFlag) : current.tags ?? []),
|
|
62
62
|
source: overrides.source ?? stringFlag(flags, 'source') ?? current.source ?? null,
|
|
63
|
+
conceptKey: overrides.conceptKey ?? stringFlag(flags, 'concept') ?? current.conceptKey ?? null,
|
|
63
64
|
deckId: deckId ?? overrides.deckId ?? current.deckId ?? null,
|
|
64
65
|
question: overrides.question ?? current.question ?? null,
|
|
65
66
|
};
|
|
@@ -166,7 +167,8 @@ export async function inboxCommand(parsed) {
|
|
|
166
167
|
' discard-all descarta todos os itens pendentes\n' +
|
|
167
168
|
' update <id> edita um item PENDENTE (merge: --file parcial.json e/ou flags\n' +
|
|
168
169
|
' --title --content --front --back --subject --subtopic\n' +
|
|
169
|
-
' --tags a,b,c --source --type)\n'
|
|
170
|
+
' --tags a,b,c --source --concept trib-art-4 --type)\n' +
|
|
171
|
+
' (--concept preserva/define o conceptKey; sem ele, o valor atual é mantido)\n');
|
|
170
172
|
if (sub) {
|
|
171
173
|
process.exitCode = 1;
|
|
172
174
|
}
|
package/dist/commands/stage.js
CHANGED
|
@@ -10,6 +10,13 @@ const LEGACY_TYPE_ALIASES = { NORMAL: 'NOTE' };
|
|
|
10
10
|
const MAX_ITEMS = 50;
|
|
11
11
|
const DEFAULT_SOURCE = 'Importação assistida (CLI)';
|
|
12
12
|
const QUESTION_KINDS = ['MULTIPLA_ESCOLHA', 'CERTO_ERRADO'];
|
|
13
|
+
/**
|
|
14
|
+
* Slug minúsculo (letras, números, hífens, até 80 chars) que identifica o conceito
|
|
15
|
+
* do item. Segmentos alfanuméricos separados por hífen único — sem hífen no
|
|
16
|
+
* início/fim nem duplo, espelhando a validação do backend (`assignConceptKey`).
|
|
17
|
+
*/
|
|
18
|
+
const CONCEPT_KEY_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
19
|
+
const CONCEPT_KEY_MAX = 80;
|
|
13
20
|
const UNLIMITED = -1;
|
|
14
21
|
/**
|
|
15
22
|
* GET /notes/import/agent-guidance, fail-open como o fetchStoredCaps: sem sessão/rede
|
|
@@ -147,6 +154,7 @@ const SCHEMA_JSON = {
|
|
|
147
154
|
subjectName: 'string? — matéria (ex.: "Direito Constitucional")',
|
|
148
155
|
subtopicName: 'string? — subtópico',
|
|
149
156
|
tags: 'string[]?',
|
|
157
|
+
conceptKey: `string? — conceito do item em slug minúsculo (letras/números/hífens, até ${CONCEPT_KEY_MAX} chars). Opcional por compatibilidade, mas FORTEMENTE RECOMENDADO em FLASHCARD/ONE_SHOT/QUESTION: cartões sobre o MESMO conceito compartilham a chave (ex.: "trib-art-4" num flashcard E numa questão do art. 4º do CTN — o whiteboard do app agrupa por conceito) e conceitos DIFERENTES usam chaves diferentes — nunca reuse a chave para outro conceito`,
|
|
150
158
|
deckName: 'string (OBRIGATÓRIO — cartão não fica sem baralho: consulte `memoring deck list`, reutilize um existente ou crie com `memoring deck create`; nome inexistente é criado no envio como PENDING — oculto no app até o 1º item aceite, que ativa o baralho e os ancestrais pendentes. A flag --deck do create vale como padrão do lote)',
|
|
151
159
|
question: 'objeto? — snapshot da questão (obrigatório quando type=QUESTION; contrato em questionContract)',
|
|
152
160
|
source: `string? — origem do material (default: "${DEFAULT_SOURCE}")`,
|
|
@@ -161,6 +169,7 @@ const SCHEMA_JSON = {
|
|
|
161
169
|
subjectName: 'Direito Constitucional',
|
|
162
170
|
deckName: 'Direito Constitucional',
|
|
163
171
|
tags: ['cf88', 'art-3'],
|
|
172
|
+
conceptKey: 'const-cf88-art-3',
|
|
164
173
|
source: 'Apostila constitucional.pdf',
|
|
165
174
|
},
|
|
166
175
|
{
|
|
@@ -169,6 +178,7 @@ const SCHEMA_JSON = {
|
|
|
169
178
|
subjectName: 'Direito Tributário',
|
|
170
179
|
deckName: 'Direito Tributário',
|
|
171
180
|
tags: ['ctn', 'art-3'],
|
|
181
|
+
conceptKey: 'trib-ctn-art-3',
|
|
172
182
|
source: 'aula-00.pdf',
|
|
173
183
|
question: {
|
|
174
184
|
kind: 'CERTO_ERRADO',
|
|
@@ -177,6 +187,32 @@ const SCHEMA_JSON = {
|
|
|
177
187
|
commentHtml: 'É a definição do art. 3º do CTN (Lei 5.172/1966).',
|
|
178
188
|
},
|
|
179
189
|
},
|
|
190
|
+
{
|
|
191
|
+
type: 'FLASHCARD',
|
|
192
|
+
title: 'CTN art. 4º — territorialidade',
|
|
193
|
+
front: 'Qual a regra de incidência dos tributos quanto à aplicação da lei (art. 4º, caput, do CTN)?',
|
|
194
|
+
back: 'Regra geral: a lei que institui o tributo aplica-se a todos os fatos geradores ocorridos no território nacional.',
|
|
195
|
+
subjectName: 'Direito Tributário',
|
|
196
|
+
deckName: 'Direito Tributário',
|
|
197
|
+
tags: ['ctn', 'art-4'],
|
|
198
|
+
conceptKey: 'trib-art-4',
|
|
199
|
+
source: 'aula-00.pdf',
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
type: 'QUESTION',
|
|
203
|
+
title: 'CTN art. 4º — exceção à territorialidade',
|
|
204
|
+
subjectName: 'Direito Tributário',
|
|
205
|
+
deckName: 'Direito Tributário',
|
|
206
|
+
tags: ['ctn', 'art-4'],
|
|
207
|
+
conceptKey: 'trib-art-4',
|
|
208
|
+
source: 'aula-00.pdf',
|
|
209
|
+
question: {
|
|
210
|
+
kind: 'CERTO_ERRADO',
|
|
211
|
+
statementHtml: 'Nos termos do art. 4º do CTN, a lei tributária brasileira NUNCA se aplica a fatos geradores ocorridos no exterior, ainda que o fato tenha produzido efeitos no Brasil.',
|
|
212
|
+
correctAlternative: 2,
|
|
213
|
+
commentHtml: 'Parágrafo único do art. 4º: a lei brasileira pode reger fatos ocorridos no exterior quando a eles se refiram dispositivos expressos da Constituição.',
|
|
214
|
+
},
|
|
215
|
+
},
|
|
180
216
|
],
|
|
181
217
|
typeCaps: 'preferência por usuário (`memoring stage caps`, vale para app e CLI) — limites são TETOS, nunca cotas: 50 é só o limite técnico por requisição, não a meta do lote; userCaps -1 = sem teto preferencial (não é incentivo a inflar), 0 = não gerar o tipo. Sem quantidade explícita no pedido, selecione só pontos realmente cobráveis, com cobertura seletiva e carga de revisão sustentável. Flags do `stage create` (--max-notes N | --max-flashcards N | --max-one-shots N | --max-questions N, ou "livre") vencem a preferência por lote.',
|
|
182
218
|
};
|
|
@@ -199,6 +235,14 @@ const SCHEMA_TEXT = `Contrato dos itens da caixa de revisão (POST /api/notes/re
|
|
|
199
235
|
subjectName? string — matéria (ex.: "Direito Constitucional")
|
|
200
236
|
subtopicName? string — subtópico
|
|
201
237
|
tags? string[]
|
|
238
|
+
conceptKey? string — conceito do item em slug minúsculo (letras, números
|
|
239
|
+
e hífens, até 80 chars). Opcional por compatibilidade, mas
|
|
240
|
+
FORTEMENTE RECOMENDADO em FLASHCARD/ONE_SHOT/QUESTION: cartões
|
|
241
|
+
sobre o MESMO conceito compartilham a MESMA chave — ex.:
|
|
242
|
+
"trib-art-4" num flashcard E numa questão do art. 4º do CTN
|
|
243
|
+
(o whiteboard do app agrupa por conceito, não por cartão) —
|
|
244
|
+
e conceitos DIFERENTES usam chaves diferentes: nunca reuse
|
|
245
|
+
uma chave para outro conceito
|
|
202
246
|
source? string — origem do material (default: "${DEFAULT_SOURCE}")
|
|
203
247
|
|
|
204
248
|
Snapshot de QUESTION (questões manuais — sem identidade TEC):
|
|
@@ -294,6 +338,7 @@ async function assignDecks(items, created, deckIds) {
|
|
|
294
338
|
subtopicName: item.subtopicName ?? null,
|
|
295
339
|
tags: item.tags ?? [],
|
|
296
340
|
source: item.source ?? null,
|
|
341
|
+
conceptKey: item.conceptKey ?? null,
|
|
297
342
|
deckId,
|
|
298
343
|
question: item.question ?? null,
|
|
299
344
|
},
|
|
@@ -410,7 +455,25 @@ function validateItems(raw) {
|
|
|
410
455
|
if (it.tags !== undefined && (!Array.isArray(it.tags) || it.tags.some((t) => typeof t !== 'string'))) {
|
|
411
456
|
fail(`${where} (${it.title}): tags deve ser um array de strings.`);
|
|
412
457
|
}
|
|
413
|
-
|
|
458
|
+
let conceptKey = null;
|
|
459
|
+
if (it.conceptKey !== undefined && it.conceptKey !== null) {
|
|
460
|
+
if (typeof it.conceptKey !== 'string') {
|
|
461
|
+
fail(`${where} (${it.title}): conceptKey deve ser uma string (slug minúsculo) ou null.`);
|
|
462
|
+
}
|
|
463
|
+
const key = it.conceptKey.trim();
|
|
464
|
+
if (key !== '') {
|
|
465
|
+
if (key.length > CONCEPT_KEY_MAX || !CONCEPT_KEY_PATTERN.test(key)) {
|
|
466
|
+
fail(`${where} (${it.title}): conceptKey "${key}" inválido — use slug minúsculo com letras, ` +
|
|
467
|
+
`números e hífens, até ${CONCEPT_KEY_MAX} chars (ex.: "trib-art-4"). Mesmo conceito, mesma chave; conceito diferente, chave diferente.`);
|
|
468
|
+
}
|
|
469
|
+
conceptKey = key;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return {
|
|
473
|
+
...it,
|
|
474
|
+
conceptKey,
|
|
475
|
+
source: typeof it.source === 'string' && it.source.trim() !== '' ? it.source : DEFAULT_SOURCE,
|
|
476
|
+
};
|
|
414
477
|
});
|
|
415
478
|
}
|
|
416
479
|
/**
|
package/dist/main.js
CHANGED
|
@@ -9,7 +9,7 @@ import { updateCommand } from './commands/update.js';
|
|
|
9
9
|
import { skillCommand } from './commands/skill.js';
|
|
10
10
|
import { parseArgs as parse } from './commands/shared.js';
|
|
11
11
|
import { newerVersionAvailable, scheduleUpdateCheck } from './update.js';
|
|
12
|
-
const VERSION = '0.
|
|
12
|
+
const VERSION = '0.13.0';
|
|
13
13
|
const HELP = `Memoring CLI — flashcards e notas por IA, direto do terminal.
|
|
14
14
|
|
|
15
15
|
Uso: memoring <comando> [subcomando] [flags]
|
package/package.json
CHANGED
|
@@ -27,7 +27,7 @@ O Memoring é um app de estudos com revisão espaçada (FSRS). A CLI `memoring`
|
|
|
27
27
|
| `memoring inbox list` | itens pendentes de revisão |
|
|
28
28
|
| `memoring inbox accept <id>\|accept-all` | aceita itens (entram nas listagens e na fila FSRS) — **decisão do usuário: só rode se ELE pedir explicitamente** |
|
|
29
29
|
| `memoring inbox discard <id>\|discard-all` | descarta item(ns) pendente(s) |
|
|
30
|
-
| `memoring inbox update <id> [--file parcial.json] [--title ...] [--front ...] [--back ...] [--tags a,b] ...` | edita um item AINDA PENDENTE (merge com o estado atual) |
|
|
30
|
+
| `memoring inbox update <id> [--file parcial.json] [--title ...] [--front ...] [--back ...] [--tags a,b] [--concept trib-art-4] ...` | edita um item AINDA PENDENTE (merge com o estado atual — `conceptKey` é preservado se não for informado) |
|
|
31
31
|
| `memoring skill` | imprime este guia |
|
|
32
32
|
| `memoring update` | atualiza a CLI (decisão do usuário — nunca rode por conta própria) |
|
|
33
33
|
|
|
@@ -51,6 +51,7 @@ Flags globais: `--json` (saída legível por máquina), `--no-color`, `--api-bas
|
|
|
51
51
|
- `deckName` **OBRIGATÓRIO** (ou `--deck` no create como padrão do lote): cartão não fica sem baralho. Use o nome de um baralho de `memoring deck list`; nome inexistente é criado no envio como **PENDING** (oculto no app até o 1º item aceite). Espelhe a hierarquia do material: matéria = baralho raiz; tema da aula/capítulo = sub-baralho criado ANTES com `deck create "<tema>" --parent "<matéria>" --pending` (o `stage create` só cria raiz pelo nome). O primeiro item aceito ativa o baralho e os ancestrais pendentes.
|
|
52
52
|
- `ONE_SHOT` = pergunta de resposta única (UMA palavra ou termo curto, texto puro). Ative o tipo sempre que o cobrável for recall de termo puro — nome de princípio/instituto, termo em latim, sigla, número de lei/artigo, data, prazo. Resposta cabe num termo → `ONE_SHOT`; exige frase ou explicação → `FLASHCARD`.
|
|
53
53
|
- `QUESTION` = questão objetiva para verificação: `question.kind` (`MULTIPLA_ESCOLHA` | `CERTO_ERRADO`), `question.statementHtml` (enunciado), `question.correctAlternative` (gabarito, int 1-based; em CERTO_ERRADO, 1 = Certo, 2 = Errado), `question.alternatives` (2 a 5 textos — só em MULTIPLA_ESCOLHA), `question.commentHtml` (explicação do gabarito). **Se o material contiver questões prontas (provas, simulados, listas C/E), APROVEITE-AS como QUESTION** preservando enunciado e gabarito — não as achate em flashcards.
|
|
54
|
+
- `conceptKey` = slug minúsculo (letras, números e hífens, até 80 chars) que identifica o CONCEITO do item. Opcional por compatibilidade, mas **fortemente recomendado em FLASHCARD/ONE_SHOT/QUESTION**. A regra é simples: cartões sobre o MESMO conceito compartilham a MESMA chave — ex.: um flashcard e uma questão sobre o art. 4º do CTN usam ambos `"trib-art-4"` — e conceitos DIFERENTES usam chaves diferentes, nunca reuse uma chave para outro conceito. No app, o whiteboard do Rascunho usa a chave para AGRUPAR por conceito: ângulos do mesmo conceito (flashcard, questão, 1-shot) contam como uma frente só nas rodadas guiadas — sem chave, cada cartão vira uma frente individual. Chaves curtas e estáveis, com contexto da matéria (ex.: `trib-ctn-art-3`, `const-cf88-art-3`), evitando chaves genéricas que fundam conceitos distintos.
|
|
54
55
|
- Preencha `source` com a origem real do material (nome do arquivo/pasta) — não use o default quando souber a origem.
|
|
55
56
|
- `subjectName`/`subtopicName` quando o material tiver matéria/subtópico claros; `tags` curtas e em minúsculas.
|
|
56
57
|
- NUNCA invente campos fora do contrato — o servidor rejeita o lote inteiro.
|