@tiagojct/subsub 0.16.0 → 0.18.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/CHANGELOG.md +28 -0
- package/README.md +9 -12
- package/dist/bench.js +1 -1
- package/dist/cli.js +2 -2
- package/dist/config.js +1 -7
- package/dist/doctor.js +1 -2
- package/dist/feedback.js +55 -0
- package/dist/init.js +7 -20
- package/dist/look.js +2 -2
- package/dist/notes.js +41 -11
- package/dist/prompt.js +4 -6
- package/dist/read.js +89 -0
- package/dist/roles.js +4 -10
- package/dist/subsub.js +161 -53
- package/dist/web.js +139 -9
- package/package.json +1 -1
- package/prompts/compare.md +1 -1
- package/prompts/gaps.md +1 -1
- package/prompts/lit.md +28 -9
- package/roles/researcher.md +8 -3
- package/src/bench.ts +1 -1
- package/src/cli.ts +2 -2
- package/src/config.ts +2 -12
- package/src/doctor.ts +1 -2
- package/src/feedback.ts +70 -0
- package/src/init.ts +6 -31
- package/src/look.ts +2 -4
- package/src/notes.ts +44 -10
- package/src/prompt.ts +6 -8
- package/src/read.ts +108 -0
- package/src/roles.ts +5 -12
- package/src/subsub.ts +154 -57
- package/src/usage.ts +1 -1
- package/src/web.ts +129 -9
- package/templates/Zotero agent.md +2 -2
- package/web/app.css +72 -2
- package/web/app.js +297 -23
- package/web/i18n.js +61 -25
- package/web/index.html +17 -16
- package/dist/profiles.js +0 -96
- package/src/profiles.ts +0 -118
package/web/i18n.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
|
|
4
4
|
export const STRINGS = {
|
|
5
5
|
en: {
|
|
6
|
-
profile: "Profile",
|
|
7
6
|
model: "Model",
|
|
8
7
|
noModel: "Connect a model",
|
|
9
8
|
noModelSend: "No model is connected yet. Choose a provider and save its key; your message is still in the box.",
|
|
@@ -20,7 +19,7 @@ export const STRINGS = {
|
|
|
20
19
|
close: "Close",
|
|
21
20
|
apply: "Apply {x}?",
|
|
22
21
|
run: "Run {x}?",
|
|
23
|
-
|
|
22
|
+
undoAsk: "Undo this change?",
|
|
24
23
|
write: "Allow writing to {x}?",
|
|
25
24
|
starbuckReport: "Write the Starbuck report to {x}?",
|
|
26
25
|
approveHint: "Nothing changes until you select Yes.",
|
|
@@ -31,9 +30,7 @@ export const STRINGS = {
|
|
|
31
30
|
toReviewHint: "Items that Sub-Sub tagged and that wait for your check (they carry the _agent tag). Select Library overview, or ask Sub-Sub to list them.",
|
|
32
31
|
serversDown: "Not running: {x}",
|
|
33
32
|
working: "Working",
|
|
34
|
-
using: "Using: {x}",
|
|
35
33
|
failed: "failed",
|
|
36
|
-
result: "Result",
|
|
37
34
|
open: "Open",
|
|
38
35
|
stopped: "Stopped.",
|
|
39
36
|
agentExit: "Sub-Sub stopped.",
|
|
@@ -91,7 +88,6 @@ export const STRINGS = {
|
|
|
91
88
|
quitDone: "Sub-Sub is closed. You can close this tab.",
|
|
92
89
|
earlier: "Earlier messages were summarised.",
|
|
93
90
|
menu: "Menu",
|
|
94
|
-
commands: "Commands",
|
|
95
91
|
error: "Error",
|
|
96
92
|
theme: "Theme",
|
|
97
93
|
themeAuto: "System",
|
|
@@ -99,7 +95,6 @@ export const STRINGS = {
|
|
|
99
95
|
themeDark: "Dark",
|
|
100
96
|
themeToggle: "Toggle theme",
|
|
101
97
|
layoutWide: "Wide",
|
|
102
|
-
layoutFocus: "Focus",
|
|
103
98
|
toggleWidth: "Toggle wide layout",
|
|
104
99
|
copy: "Copy",
|
|
105
100
|
copied: "Copied",
|
|
@@ -107,6 +102,26 @@ export const STRINGS = {
|
|
|
107
102
|
searchConversations: "Search conversations",
|
|
108
103
|
export: "Export",
|
|
109
104
|
exportTitle: "Export conversation",
|
|
105
|
+
exportHeading: "Sub-Sub conversation",
|
|
106
|
+
exportUser: "You",
|
|
107
|
+
exportMode: "Mode",
|
|
108
|
+
notes: "Notes",
|
|
109
|
+
notesHint: "The notes in your Sub-Sub folder",
|
|
110
|
+
allNotes: "All notes",
|
|
111
|
+
properties: "Properties",
|
|
112
|
+
downloadCsv: "Download CSV",
|
|
113
|
+
filterNotes: "Filter notes",
|
|
114
|
+
noNotes: "No notes yet.",
|
|
115
|
+
openInApp: "Open in app",
|
|
116
|
+
librarySearch: "Search your library",
|
|
117
|
+
searching: "Searching...",
|
|
118
|
+
noItems: "Nothing found.",
|
|
119
|
+
readItem: "Read",
|
|
120
|
+
noteItem: "Note",
|
|
121
|
+
rename: "Rename",
|
|
122
|
+
renamePrompt: "A new name for this conversation",
|
|
123
|
+
trash: "Delete",
|
|
124
|
+
trashConfirm: "Move this conversation to the trash folder (~/.subsub/trash)? You can move it back from there.",
|
|
110
125
|
confirmShortcutHint: "Y to approve, N to decline",
|
|
111
126
|
starbuck: "Reference checks (Starbuck)",
|
|
112
127
|
starbuckHint: "Checks that cited works exist, match their citation and were not retracted. Sub-Sub restarts when you change this.",
|
|
@@ -128,7 +143,6 @@ export const STRINGS = {
|
|
|
128
143
|
groupLibrary: "Library",
|
|
129
144
|
},
|
|
130
145
|
pt: {
|
|
131
|
-
profile: "Perfil",
|
|
132
146
|
model: "Modelo",
|
|
133
147
|
noModel: "Ligar um modelo",
|
|
134
148
|
noModelSend: "Ainda não há um modelo ligado. Escolha um fornecedor e guarde a chave; a sua mensagem continua na caixa.",
|
|
@@ -145,7 +159,7 @@ export const STRINGS = {
|
|
|
145
159
|
close: "Fechar",
|
|
146
160
|
apply: "Confirmar: {x}?",
|
|
147
161
|
run: "Executar {x}?",
|
|
148
|
-
|
|
162
|
+
undoAsk: "Desfazer esta alteração?",
|
|
149
163
|
write: "Permitir escrever em {x}?",
|
|
150
164
|
starbuckReport: "Escrever o relatório do Starbuck em {x}?",
|
|
151
165
|
approveHint: "Nada muda até selecionar Sim.",
|
|
@@ -156,9 +170,7 @@ export const STRINGS = {
|
|
|
156
170
|
toReviewHint: "Itens que o Sub-Sub etiquetou e que esperam a sua verificação (têm a etiqueta _agent). Selecione Resumo da biblioteca, ou peça ao Sub-Sub para os listar.",
|
|
157
171
|
serversDown: "Parados: {x}",
|
|
158
172
|
working: "A trabalhar",
|
|
159
|
-
using: "A usar: {x}",
|
|
160
173
|
failed: "falhou",
|
|
161
|
-
result: "Resultado",
|
|
162
174
|
open: "Abrir",
|
|
163
175
|
stopped: "Parado.",
|
|
164
176
|
agentExit: "O Sub-Sub parou.",
|
|
@@ -216,7 +228,6 @@ export const STRINGS = {
|
|
|
216
228
|
quitDone: "O Sub-Sub está fechado. Pode fechar este separador.",
|
|
217
229
|
earlier: "As mensagens anteriores foram resumidas.",
|
|
218
230
|
menu: "Menu",
|
|
219
|
-
commands: "Comandos",
|
|
220
231
|
error: "Erro",
|
|
221
232
|
theme: "Tema",
|
|
222
233
|
themeAuto: "Sistema",
|
|
@@ -224,7 +235,6 @@ export const STRINGS = {
|
|
|
224
235
|
themeDark: "Escuro",
|
|
225
236
|
themeToggle: "Mudar tema",
|
|
226
237
|
layoutWide: "Largo",
|
|
227
|
-
layoutFocus: "Foco",
|
|
228
238
|
toggleWidth: "Mudar largura do ecrã",
|
|
229
239
|
copy: "Copiar",
|
|
230
240
|
copied: "Copiado",
|
|
@@ -232,6 +242,26 @@ export const STRINGS = {
|
|
|
232
242
|
searchConversations: "Procurar conversas",
|
|
233
243
|
export: "Exportar",
|
|
234
244
|
exportTitle: "Exportar conversa",
|
|
245
|
+
exportHeading: "Conversa do Sub-Sub",
|
|
246
|
+
exportUser: "Utilizador",
|
|
247
|
+
exportMode: "Modo",
|
|
248
|
+
notes: "Notas",
|
|
249
|
+
notesHint: "As notas da sua pasta do Sub-Sub",
|
|
250
|
+
allNotes: "Todas as notas",
|
|
251
|
+
properties: "Propriedades",
|
|
252
|
+
downloadCsv: "Transferir CSV",
|
|
253
|
+
filterNotes: "Filtrar notas",
|
|
254
|
+
noNotes: "Ainda não há notas.",
|
|
255
|
+
openInApp: "Abrir na aplicação",
|
|
256
|
+
librarySearch: "Pesquisar na biblioteca",
|
|
257
|
+
searching: "A pesquisar...",
|
|
258
|
+
noItems: "Nada encontrado.",
|
|
259
|
+
readItem: "Ler",
|
|
260
|
+
noteItem: "Nota",
|
|
261
|
+
rename: "Mudar o nome",
|
|
262
|
+
renamePrompt: "Um novo nome para esta conversa",
|
|
263
|
+
trash: "Apagar",
|
|
264
|
+
trashConfirm: "Mover esta conversa para a pasta do lixo (~/.subsub/trash)? Pode trazê-la de volta a partir daí.",
|
|
235
265
|
confirmShortcutHint: "S para aprovar, N para recusar",
|
|
236
266
|
starbuck: "Verificação de referências (Starbuck)",
|
|
237
267
|
starbuckHint: "Verifica se as obras citadas existem, correspondem à citação e não foram retratadas. O Sub-Sub reinicia quando muda esta opção.",
|
|
@@ -255,23 +285,26 @@ export const STRINGS = {
|
|
|
255
285
|
};
|
|
256
286
|
|
|
257
287
|
/**
|
|
258
|
-
* Buttons in the side panel, in two groups.
|
|
259
|
-
*
|
|
288
|
+
* Buttons in the side panel, in two groups. A button puts the command in the message box; `send` runs it at once;
|
|
289
|
+
* `item` opens the library search, whose results have their own buttons.
|
|
290
|
+
* The Librarian sees the Library group only. `needs` limits a button to an add-on.
|
|
260
291
|
*/
|
|
261
292
|
export const ACTIONS = {
|
|
262
293
|
research: [
|
|
263
|
-
{ cmd: "
|
|
264
|
-
{ cmd: "
|
|
265
|
-
{ cmd: "lit
|
|
266
|
-
{ cmd: "
|
|
267
|
-
{ cmd: "
|
|
268
|
-
{ cmd: "
|
|
269
|
-
{ cmd: "
|
|
270
|
-
{ cmd: "
|
|
294
|
+
{ cmd: "read", send: true, en: "Read a paper", pt: "Ler um artigo" },
|
|
295
|
+
{ cmd: "lit", en: "Literature review", pt: "Revisão da literatura" },
|
|
296
|
+
{ cmd: "lit reading list:", en: "Reading list", pt: "Lista de leitura" },
|
|
297
|
+
{ cmd: "compare", en: "Compare sources", pt: "Comparar fontes" },
|
|
298
|
+
{ cmd: "lit-note", item: true, en: "Literature note", pt: "Nota de literatura" },
|
|
299
|
+
{ cmd: "synthesis", en: "Synthesis", pt: "Síntese" },
|
|
300
|
+
{ cmd: "gaps", en: "What is missing", pt: "O que falta" },
|
|
301
|
+
{ cmd: "manuscript", en: "Check a manuscript", pt: "Verificar um manuscrito" },
|
|
302
|
+
{ cmd: "verify", needs: "starbuck", en: "Check references", pt: "Verificar referências" },
|
|
303
|
+
{ cmd: "review", en: "Review a manuscript", pt: "Rever um manuscrito" },
|
|
271
304
|
{ cmd: "alert", send: true, en: "New publications", pt: "Novas publicações" },
|
|
272
|
-
{ cmd: "request-copy",
|
|
273
|
-
{ cmd: "ai-statement",
|
|
274
|
-
{ cmd: "digest", send: true,
|
|
305
|
+
{ cmd: "request-copy", en: "Ask an author for a copy", pt: "Pedir uma cópia ao autor" },
|
|
306
|
+
{ cmd: "ai-statement", en: "Statement on AI use", pt: "Declaração de uso de IA" },
|
|
307
|
+
{ cmd: "digest", send: true, en: "Digest of the week", pt: "Resumo da semana" },
|
|
275
308
|
],
|
|
276
309
|
library: [
|
|
277
310
|
{ cmd: "subsub", send: true, en: "Library overview", pt: "Resumo da biblioteca" },
|
|
@@ -280,6 +313,7 @@ export const ACTIONS = {
|
|
|
280
313
|
{ cmd: "import-queue", send: true, en: "Import the queue", pt: "Importar a fila" },
|
|
281
314
|
{ cmd: "history", send: true, en: "Recent changes", pt: "Alterações recentes" },
|
|
282
315
|
{ cmd: "undo", send: true, en: "Undo the last change", pt: "Desfazer a última alteração" },
|
|
316
|
+
{ cmd: "feedback", en: "Report a problem", pt: "Comunicar um problema" },
|
|
283
317
|
],
|
|
284
318
|
};
|
|
285
319
|
|
|
@@ -301,6 +335,7 @@ export const SUGGESTIONS = {
|
|
|
301
335
|
export const TOOLS = {
|
|
302
336
|
en: {
|
|
303
337
|
find_items: "search the library",
|
|
338
|
+
get_figure: "cut a figure out of the PDF",
|
|
304
339
|
standalone_items: "list files without a parent item",
|
|
305
340
|
set_parent_items: "give files a parent item",
|
|
306
341
|
find_reference: "look up a reference",
|
|
@@ -361,6 +396,7 @@ export const TOOLS = {
|
|
|
361
396
|
},
|
|
362
397
|
pt: {
|
|
363
398
|
find_items: "pesquisar na biblioteca",
|
|
399
|
+
get_figure: "recortar uma figura do PDF",
|
|
364
400
|
standalone_items: "listar ficheiros sem item principal",
|
|
365
401
|
set_parent_items: "dar um item principal aos ficheiros",
|
|
366
402
|
find_reference: "procurar uma referência",
|
package/web/index.html
CHANGED
|
@@ -21,14 +21,7 @@
|
|
|
21
21
|
</div>
|
|
22
22
|
<div class="status">
|
|
23
23
|
<span class="library" id="library"><span class="library-dot" aria-hidden="true"></span><span class="library-text"></span></span>
|
|
24
|
-
<
|
|
25
|
-
<select id="profile">
|
|
26
|
-
<option value="reader">Reader</option>
|
|
27
|
-
<option value="scholar">Scholar</option>
|
|
28
|
-
<option value="author">Author</option>
|
|
29
|
-
<option value="editor">Editor</option>
|
|
30
|
-
</select>
|
|
31
|
-
</label>
|
|
24
|
+
<button type="button" class="chip-btn" id="notes-btn" aria-controls="note-pane" aria-expanded="false" data-i18n="notes" data-i18n-title="notesHint">Notes</button>
|
|
32
25
|
<button type="button" class="chip-btn model-btn wide-only" id="model-btn"></button>
|
|
33
26
|
<button type="button" class="icon-btn wide-only" id="width-btn" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 12h16M4 12l3.5-3.5M4 12l3.5 3.5M20 12l-3.5-3.5M20 12l-3.5 3.5"/></svg><span class="visually-hidden" id="width-btn-text">Wide</span></button>
|
|
34
27
|
<button type="button" class="icon-btn" id="theme-btn"></button>
|
|
@@ -38,14 +31,6 @@
|
|
|
38
31
|
<aside class="side" id="side">
|
|
39
32
|
<button type="button" class="new-btn" id="new-btn"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg><span data-i18n="newConversation">New conversation</span></button>
|
|
40
33
|
<section class="phone-only settings">
|
|
41
|
-
<label><span data-i18n="profile">Profile</span>
|
|
42
|
-
<select id="profile-side">
|
|
43
|
-
<option value="reader">Reader</option>
|
|
44
|
-
<option value="scholar">Scholar</option>
|
|
45
|
-
<option value="author">Author</option>
|
|
46
|
-
<option value="editor">Editor</option>
|
|
47
|
-
</select>
|
|
48
|
-
</label>
|
|
49
34
|
<label><span data-i18n="model">Model</span>
|
|
50
35
|
<button type="button" class="secondary model-btn" id="model-btn-side"></button>
|
|
51
36
|
</label>
|
|
@@ -53,6 +38,11 @@
|
|
|
53
38
|
<button type="button" class="secondary" id="theme-btn-side"></button>
|
|
54
39
|
</label>
|
|
55
40
|
</section>
|
|
41
|
+
<section>
|
|
42
|
+
<h2 data-i18n="groupLibrary">Library</h2>
|
|
43
|
+
<input type="search" id="library-search" class="search" data-i18n-placeholder="librarySearch" placeholder="Search your library" autocomplete="off">
|
|
44
|
+
<ul class="items" id="items" aria-live="polite"></ul>
|
|
45
|
+
</section>
|
|
56
46
|
<section>
|
|
57
47
|
<h2 data-i18n="actions">Actions</h2>
|
|
58
48
|
<div class="actions" id="actions"></div>
|
|
@@ -91,6 +81,17 @@
|
|
|
91
81
|
</div>
|
|
92
82
|
</form>
|
|
93
83
|
</main>
|
|
84
|
+
|
|
85
|
+
<aside class="note-pane" id="note-pane" hidden>
|
|
86
|
+
<div class="note-head">
|
|
87
|
+
<button type="button" class="link-btn" id="note-back" data-i18n="allNotes">All notes</button>
|
|
88
|
+
<span class="note-name" id="note-name"></span>
|
|
89
|
+
<button type="button" class="link-btn" id="note-app" data-i18n="openInApp" hidden>Open in app</button>
|
|
90
|
+
<button type="button" class="link-btn" id="note-close" data-i18n="close">Close</button>
|
|
91
|
+
</div>
|
|
92
|
+
<input type="search" id="note-filter" class="search" data-i18n-placeholder="filterNotes" placeholder="Filter notes" autocomplete="off">
|
|
93
|
+
<div class="note-body" id="note-body"></div>
|
|
94
|
+
</aside>
|
|
94
95
|
</div>
|
|
95
96
|
|
|
96
97
|
<dialog id="dialog" class="modal">
|
package/dist/profiles.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Profiles: how much Sub-Sub does for the user. Named after the work, not the
|
|
3
|
-
* person: a professor new to a field can choose Reader, a student can choose
|
|
4
|
-
* Scholar. A profile is the user's own choice (/profile changes it), not a lock.
|
|
5
|
-
*
|
|
6
|
-
* - reader: explains each step; reading notes are quotes with page numbers and
|
|
7
|
-
* questions; no summaries or syntheses; /lit gives a reading list;
|
|
8
|
-
* no bulk library changes.
|
|
9
|
-
* - scholar: literature notes, syntheses, searches, alerts; all library changes.
|
|
10
|
-
* - author: scholar plus manuscript work: citation check, bibliography, comments
|
|
11
|
-
* on the argument. Does not write the manuscript's paragraphs.
|
|
12
|
-
* - editor: everything, including drafting text for a manuscript on request.
|
|
13
|
-
*/
|
|
14
|
-
const BULK_LIBRARY = ["rename_tags", "remove_tags", "remove_automatic_tags", "trash_items", "update_fields", "repair_metadata"].map((n) => `zotero_${n}`);
|
|
15
|
-
const MANUSCRIPT = ["scholar_check_manuscript", "scholar_export_bibliography"];
|
|
16
|
-
export const PROFILE_SPECS = {
|
|
17
|
-
reader: {
|
|
18
|
-
name: "reader",
|
|
19
|
-
label: "Reader",
|
|
20
|
-
summary: "explains each step; reading notes are quotes and questions; /lit gives a reading list; no summaries; no bulk library changes",
|
|
21
|
-
without: [...BULK_LIBRARY, ...MANUSCRIPT],
|
|
22
|
-
withoutPrompts: ["compare", "review", "digest"],
|
|
23
|
-
batch: 10,
|
|
24
|
-
rules: [
|
|
25
|
-
"Profile: Reader. {{User}} is learning to work with the literature and wants to do the reading and the writing.",
|
|
26
|
-
"- Before each step, say in one or two lines what you will do and why.",
|
|
27
|
-
"- A literature note is a reading note: the full reference, then direct quotes with page numbers (or section names), and under each quote one question for {{user}} to answer. Do not write summaries, syntheses, conclusions or paragraphs that {{user}} could hand in as their own text. When a prompt or the shared rules ask for a literature note or a synthesis, make a reading note instead and say so.",
|
|
28
|
-
"- For searches, list works with one line each on what they study, not on what they conclude.",
|
|
29
|
-
"- /lit gives a reading list, not a review: plan, search, screen and read as the prompt says, then write the note in the Reader form that the prompt gives (no answer, no agreement or disagreement, no conclusions).",
|
|
30
|
-
"- If {{user}} asks for a summary, a synthesis or text for an assignment, say that the Reader profile does not write these, and offer quotes and questions. {{User}} can change the profile with /profile.",
|
|
31
|
-
"- Tag review notes: at most 10 items. Explain each proposed tag in the Reason column.",
|
|
32
|
-
].join("\n"),
|
|
33
|
-
},
|
|
34
|
-
scholar: {
|
|
35
|
-
name: "scholar",
|
|
36
|
-
label: "Scholar",
|
|
37
|
-
summary: "literature notes, syntheses, searches and alerts; all library changes",
|
|
38
|
-
without: MANUSCRIPT,
|
|
39
|
-
withoutPrompts: ["review"],
|
|
40
|
-
batch: 25,
|
|
41
|
-
rules: [
|
|
42
|
-
"Profile: Scholar.",
|
|
43
|
-
"- Write literature notes and syntheses from what you read, with a source for every claim.",
|
|
44
|
-
"- Do not draft text for {{user}}'s manuscripts, theses or assignments. If asked, say that the Author and Editor profiles help with manuscripts (/profile).",
|
|
45
|
-
"- Tag review notes: 25 items.",
|
|
46
|
-
].join("\n"),
|
|
47
|
-
},
|
|
48
|
-
author: {
|
|
49
|
-
name: "author",
|
|
50
|
-
label: "Author",
|
|
51
|
-
summary: "Scholar plus manuscripts: citation check, bibliography, comments on the argument",
|
|
52
|
-
without: [],
|
|
53
|
-
withoutPrompts: [],
|
|
54
|
-
batch: 25,
|
|
55
|
-
rules: [
|
|
56
|
-
"Profile: Author.",
|
|
57
|
-
"- Write literature notes and syntheses from what you read, with a source for every claim.",
|
|
58
|
-
"- Help with {{user}}'s manuscripts: check citations against the library, export the bibliography, and comment on the argument, the structure and the evidence that is missing, with the sources that could support each point.",
|
|
59
|
-
"- Do not write the manuscript's paragraphs. Say what is missing and where the support is; {{user}} writes the text. The Editor profile drafts text (/profile).",
|
|
60
|
-
"- Tag review notes: 25 items.",
|
|
61
|
-
].join("\n"),
|
|
62
|
-
},
|
|
63
|
-
editor: {
|
|
64
|
-
name: "editor",
|
|
65
|
-
label: "Editor",
|
|
66
|
-
summary: "everything, including drafting manuscript text on request",
|
|
67
|
-
without: [],
|
|
68
|
-
withoutPrompts: [],
|
|
69
|
-
batch: 25,
|
|
70
|
-
rules: [
|
|
71
|
-
"Profile: Editor. All tools.",
|
|
72
|
-
"- Write literature notes and syntheses from what you read, with a source for every claim.",
|
|
73
|
-
"- When {{user}} asks, draft text for a manuscript: cite library items as [@citekey], use only claims from sources you read, and mark drafted text clearly so that {{user}} can check it.",
|
|
74
|
-
"- Tag review notes: 25 items unless {{user}} asks for more.",
|
|
75
|
-
].join("\n"),
|
|
76
|
-
},
|
|
77
|
-
};
|
|
78
|
-
export function profileSpec(p) {
|
|
79
|
-
return PROFILE_SPECS[p];
|
|
80
|
-
}
|
|
81
|
-
/** Why a prompt command does not run in this profile, or undefined when it does. */
|
|
82
|
-
export function promptBlocked(text, profile) {
|
|
83
|
-
const m = /^\/([\w-]+)(?:\s|$)/.exec(text.trim());
|
|
84
|
-
if (!m || !PROFILE_SPECS[profile].withoutPrompts.includes(m[1]))
|
|
85
|
-
return undefined;
|
|
86
|
-
const allowed = Object.values(PROFILE_SPECS)
|
|
87
|
-
.filter((s) => !s.withoutPrompts.includes(m[1]))
|
|
88
|
-
.map((s) => s.label)
|
|
89
|
-
.join(", ");
|
|
90
|
-
return `/${m[1]} is not part of the ${PROFILE_SPECS[profile].label} profile (it is in: ${allowed}). Change the profile with /profile.`;
|
|
91
|
-
}
|
|
92
|
-
export function profileList(current) {
|
|
93
|
-
return Object.values(PROFILE_SPECS)
|
|
94
|
-
.map((s) => `${s.name === current ? "*" : " "} ${s.label.padEnd(8)} ${s.summary}`)
|
|
95
|
-
.join("\n");
|
|
96
|
-
}
|
package/src/profiles.ts
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Profiles: how much Sub-Sub does for the user. Named after the work, not the
|
|
3
|
-
* person: a professor new to a field can choose Reader, a student can choose
|
|
4
|
-
* Scholar. A profile is the user's own choice (/profile changes it), not a lock.
|
|
5
|
-
*
|
|
6
|
-
* - reader: explains each step; reading notes are quotes with page numbers and
|
|
7
|
-
* questions; no summaries or syntheses; /lit gives a reading list;
|
|
8
|
-
* no bulk library changes.
|
|
9
|
-
* - scholar: literature notes, syntheses, searches, alerts; all library changes.
|
|
10
|
-
* - author: scholar plus manuscript work: citation check, bibliography, comments
|
|
11
|
-
* on the argument. Does not write the manuscript's paragraphs.
|
|
12
|
-
* - editor: everything, including drafting text for a manuscript on request.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import type { Profile } from "./config.ts";
|
|
16
|
-
|
|
17
|
-
export interface ProfileSpec {
|
|
18
|
-
name: Profile;
|
|
19
|
-
label: string;
|
|
20
|
-
summary: string;
|
|
21
|
-
/** Tools this profile does not offer (full names). */
|
|
22
|
-
without: string[];
|
|
23
|
-
/** Prompt commands this profile does not run (names without the slash). */
|
|
24
|
-
withoutPrompts: string[];
|
|
25
|
-
/** Items per review note and per batch. */
|
|
26
|
-
batch: number;
|
|
27
|
-
/** Added to the system prompt. {{user}} is the user's name or "the user". */
|
|
28
|
-
rules: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const BULK_LIBRARY = ["rename_tags", "remove_tags", "remove_automatic_tags", "trash_items", "update_fields", "repair_metadata"].map(
|
|
32
|
-
(n) => `zotero_${n}`,
|
|
33
|
-
);
|
|
34
|
-
const MANUSCRIPT = ["scholar_check_manuscript", "scholar_export_bibliography"];
|
|
35
|
-
|
|
36
|
-
export const PROFILE_SPECS: Record<Profile, ProfileSpec> = {
|
|
37
|
-
reader: {
|
|
38
|
-
name: "reader",
|
|
39
|
-
label: "Reader",
|
|
40
|
-
summary: "explains each step; reading notes are quotes and questions; /lit gives a reading list; no summaries; no bulk library changes",
|
|
41
|
-
without: [...BULK_LIBRARY, ...MANUSCRIPT],
|
|
42
|
-
withoutPrompts: ["compare", "review", "digest"],
|
|
43
|
-
batch: 10,
|
|
44
|
-
rules: [
|
|
45
|
-
"Profile: Reader. {{User}} is learning to work with the literature and wants to do the reading and the writing.",
|
|
46
|
-
"- Before each step, say in one or two lines what you will do and why.",
|
|
47
|
-
"- A literature note is a reading note: the full reference, then direct quotes with page numbers (or section names), and under each quote one question for {{user}} to answer. Do not write summaries, syntheses, conclusions or paragraphs that {{user}} could hand in as their own text. When a prompt or the shared rules ask for a literature note or a synthesis, make a reading note instead and say so.",
|
|
48
|
-
"- For searches, list works with one line each on what they study, not on what they conclude.",
|
|
49
|
-
"- /lit gives a reading list, not a review: plan, search, screen and read as the prompt says, then write the note in the Reader form that the prompt gives (no answer, no agreement or disagreement, no conclusions).",
|
|
50
|
-
"- If {{user}} asks for a summary, a synthesis or text for an assignment, say that the Reader profile does not write these, and offer quotes and questions. {{User}} can change the profile with /profile.",
|
|
51
|
-
"- Tag review notes: at most 10 items. Explain each proposed tag in the Reason column.",
|
|
52
|
-
].join("\n"),
|
|
53
|
-
},
|
|
54
|
-
scholar: {
|
|
55
|
-
name: "scholar",
|
|
56
|
-
label: "Scholar",
|
|
57
|
-
summary: "literature notes, syntheses, searches and alerts; all library changes",
|
|
58
|
-
without: MANUSCRIPT,
|
|
59
|
-
withoutPrompts: ["review"],
|
|
60
|
-
batch: 25,
|
|
61
|
-
rules: [
|
|
62
|
-
"Profile: Scholar.",
|
|
63
|
-
"- Write literature notes and syntheses from what you read, with a source for every claim.",
|
|
64
|
-
"- Do not draft text for {{user}}'s manuscripts, theses or assignments. If asked, say that the Author and Editor profiles help with manuscripts (/profile).",
|
|
65
|
-
"- Tag review notes: 25 items.",
|
|
66
|
-
].join("\n"),
|
|
67
|
-
},
|
|
68
|
-
author: {
|
|
69
|
-
name: "author",
|
|
70
|
-
label: "Author",
|
|
71
|
-
summary: "Scholar plus manuscripts: citation check, bibliography, comments on the argument",
|
|
72
|
-
without: [],
|
|
73
|
-
withoutPrompts: [],
|
|
74
|
-
batch: 25,
|
|
75
|
-
rules: [
|
|
76
|
-
"Profile: Author.",
|
|
77
|
-
"- Write literature notes and syntheses from what you read, with a source for every claim.",
|
|
78
|
-
"- Help with {{user}}'s manuscripts: check citations against the library, export the bibliography, and comment on the argument, the structure and the evidence that is missing, with the sources that could support each point.",
|
|
79
|
-
"- Do not write the manuscript's paragraphs. Say what is missing and where the support is; {{user}} writes the text. The Editor profile drafts text (/profile).",
|
|
80
|
-
"- Tag review notes: 25 items.",
|
|
81
|
-
].join("\n"),
|
|
82
|
-
},
|
|
83
|
-
editor: {
|
|
84
|
-
name: "editor",
|
|
85
|
-
label: "Editor",
|
|
86
|
-
summary: "everything, including drafting manuscript text on request",
|
|
87
|
-
without: [],
|
|
88
|
-
withoutPrompts: [],
|
|
89
|
-
batch: 25,
|
|
90
|
-
rules: [
|
|
91
|
-
"Profile: Editor. All tools.",
|
|
92
|
-
"- Write literature notes and syntheses from what you read, with a source for every claim.",
|
|
93
|
-
"- When {{user}} asks, draft text for a manuscript: cite library items as [@citekey], use only claims from sources you read, and mark drafted text clearly so that {{user}} can check it.",
|
|
94
|
-
"- Tag review notes: 25 items unless {{user}} asks for more.",
|
|
95
|
-
].join("\n"),
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
export function profileSpec(p: Profile): ProfileSpec {
|
|
100
|
-
return PROFILE_SPECS[p];
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/** Why a prompt command does not run in this profile, or undefined when it does. */
|
|
104
|
-
export function promptBlocked(text: string, profile: Profile): string | undefined {
|
|
105
|
-
const m = /^\/([\w-]+)(?:\s|$)/.exec(text.trim());
|
|
106
|
-
if (!m || !PROFILE_SPECS[profile].withoutPrompts.includes(m[1])) return undefined;
|
|
107
|
-
const allowed = Object.values(PROFILE_SPECS)
|
|
108
|
-
.filter((s) => !s.withoutPrompts.includes(m[1]))
|
|
109
|
-
.map((s) => s.label)
|
|
110
|
-
.join(", ");
|
|
111
|
-
return `/${m[1]} is not part of the ${PROFILE_SPECS[profile].label} profile (it is in: ${allowed}). Change the profile with /profile.`;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export function profileList(current?: Profile): string {
|
|
115
|
-
return Object.values(PROFILE_SPECS)
|
|
116
|
-
.map((s) => `${s.name === current ? "*" : " "} ${s.label.padEnd(8)} ${s.summary}`)
|
|
117
|
-
.join("\n");
|
|
118
|
-
}
|