@tiagojct/subsub 0.12.1 → 0.13.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/CHANGELOG.md +8 -2
- package/dist/preview.js +17 -0
- package/dist/subsub.js +7 -1
- package/package.json +1 -1
- package/src/preview.ts +14 -0
- package/src/subsub.ts +7 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
-
Sub-Sub follows the version numbers of npm: a change in the second number (0.
|
|
3
|
+
Sub-Sub follows the version numbers of npm: a change in the second number (0.13) adds features or changes how you use it; a change in the third (0.13.1) only fixes.
|
|
4
4
|
|
|
5
|
-
## 0.
|
|
5
|
+
## 0.13.1 (2026-10-07)
|
|
6
|
+
|
|
7
|
+
- A change that would change nothing (for example, citekeys for items that already have one) is no longer offered for approval. Sub-Sub says why instead.
|
|
8
|
+
|
|
9
|
+
## 0.13.0 (2026-10-07)
|
|
10
|
+
|
|
11
|
+
The same changes were published first as 0.12.1.
|
|
6
12
|
|
|
7
13
|
Files and notes without a parent item (Zotero server 0.5.5):
|
|
8
14
|
|
package/dist/preview.js
CHANGED
|
@@ -196,6 +196,23 @@ export function formatPreview(tool, preview, lang = "en") {
|
|
|
196
196
|
lines.push(s(p, 1500));
|
|
197
197
|
return lines.join("\n");
|
|
198
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* True when a preview has nothing to apply: every count it gives is zero and it creates,
|
|
201
|
+
* writes or undoes nothing. Such a change is not offered for approval.
|
|
202
|
+
*/
|
|
203
|
+
export function isEmptyPreview(preview) {
|
|
204
|
+
if (!preview || typeof preview !== "object")
|
|
205
|
+
return false;
|
|
206
|
+
const p = preview;
|
|
207
|
+
const counts = ["would_import", "would_attach", "would_set_parent"].filter((k) => Array.isArray(p[k]));
|
|
208
|
+
if (typeof p.would_change !== "number" && !counts.length)
|
|
209
|
+
return false;
|
|
210
|
+
if (typeof p.would_change === "number" && p.would_change > 0)
|
|
211
|
+
return false;
|
|
212
|
+
if (counts.some((k) => p[k].length > 0))
|
|
213
|
+
return false;
|
|
214
|
+
return !["would_create", "undoing", "summary", "note_preview"].some((k) => p[k]);
|
|
215
|
+
}
|
|
199
216
|
export function describeArgs(input) {
|
|
200
217
|
return Object.entries(input)
|
|
201
218
|
.map(([k, v]) => `${k}: ${s(v, 120)}`)
|
package/dist/subsub.js
CHANGED
|
@@ -24,7 +24,7 @@ import { profileList, profileSpec, promptBlocked } from "./profiles.js";
|
|
|
24
24
|
import { coerceArgs, loosenArrays, resolvePathArgs } from "./args.js";
|
|
25
25
|
import { applyEdits, checkLiteratureNote } from "./notes.js";
|
|
26
26
|
import { buildPolicy, isSecret, judgePath, normalizeToolPath, realish, within } from "./paths.js";
|
|
27
|
-
import { describeArgs, formatPreview } from "./preview.js";
|
|
27
|
+
import { describeArgs, formatPreview, isEmptyPreview } from "./preview.js";
|
|
28
28
|
import { perMinuteWait, providerTrouble, TROUBLE_TEXT, TROUBLE_TEXT_PT } from "./keys.js";
|
|
29
29
|
import { headerLines, paintPreview, QUOTES, schemeFromAnsi, themeName } from "./look.js";
|
|
30
30
|
import { systemAddition } from "./prompt.js";
|
|
@@ -442,6 +442,12 @@ export async function createSubsub(pi, deps = {}) {
|
|
|
442
442
|
}
|
|
443
443
|
if (preview.isError)
|
|
444
444
|
return { block: true, reason: preview.text };
|
|
445
|
+
if (isEmptyPreview(preview.data)) {
|
|
446
|
+
return {
|
|
447
|
+
block: true,
|
|
448
|
+
reason: `Nothing to apply: the preview changes no item, so ${user} was not asked. Tell ${user} why in plain words; do not call ${name} again with the same input. Preview: ${JSON.stringify(preview.data).slice(0, 2000)}`,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
445
451
|
const title = L(`Sub-Sub: apply ${name.replace(/^(zotero|scholar)_/, "")}?`, `Sub-Sub: aplicar ${name.replace(/^(zotero|scholar)_/, "")}?`);
|
|
446
452
|
let shown = formatPreview(name, preview.data ?? preview.text, lang);
|
|
447
453
|
// The dialog may stay open for minutes. Before applying, compute the preview again: if the
|
package/package.json
CHANGED
package/src/preview.ts
CHANGED
|
@@ -207,6 +207,20 @@ export function formatPreview(tool: string, preview: unknown, lang: Lang = "en")
|
|
|
207
207
|
return lines.join("\n");
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
/**
|
|
211
|
+
* True when a preview has nothing to apply: every count it gives is zero and it creates,
|
|
212
|
+
* writes or undoes nothing. Such a change is not offered for approval.
|
|
213
|
+
*/
|
|
214
|
+
export function isEmptyPreview(preview: unknown): boolean {
|
|
215
|
+
if (!preview || typeof preview !== "object") return false;
|
|
216
|
+
const p = preview as Obj;
|
|
217
|
+
const counts = ["would_import", "would_attach", "would_set_parent"].filter((k) => Array.isArray(p[k]));
|
|
218
|
+
if (typeof p.would_change !== "number" && !counts.length) return false;
|
|
219
|
+
if (typeof p.would_change === "number" && p.would_change > 0) return false;
|
|
220
|
+
if (counts.some((k) => (p[k] as unknown[]).length > 0)) return false;
|
|
221
|
+
return !["would_create", "undoing", "summary", "note_preview"].some((k) => p[k]);
|
|
222
|
+
}
|
|
223
|
+
|
|
210
224
|
export function describeArgs(input: Record<string, unknown>): string {
|
|
211
225
|
return Object.entries(input)
|
|
212
226
|
.map(([k, v]) => `${k}: ${s(v, 120)}`)
|
package/src/subsub.ts
CHANGED
|
@@ -41,7 +41,7 @@ import { profileList, profileSpec, promptBlocked } from "./profiles.ts";
|
|
|
41
41
|
import { coerceArgs, loosenArrays, resolvePathArgs } from "./args.ts";
|
|
42
42
|
import { applyEdits, checkLiteratureNote } from "./notes.ts";
|
|
43
43
|
import { buildPolicy, isSecret, judgePath, normalizeToolPath, realish, within } from "./paths.ts";
|
|
44
|
-
import { describeArgs, formatPreview } from "./preview.ts";
|
|
44
|
+
import { describeArgs, formatPreview, isEmptyPreview } from "./preview.ts";
|
|
45
45
|
import { perMinuteWait, providerTrouble, TROUBLE_TEXT, TROUBLE_TEXT_PT } from "./keys.ts";
|
|
46
46
|
import { headerLines, type LibraryState, paintPreview, QUOTES, type Scheme, schemeFromAnsi, themeName } from "./look.ts";
|
|
47
47
|
import { systemAddition } from "./prompt.ts";
|
|
@@ -459,6 +459,12 @@ export async function createSubsub(pi: ExtensionAPI, deps: SubsubDeps = {}): Pro
|
|
|
459
459
|
return { block: true, reason: `Preview failed: ${(err as Error).message}` };
|
|
460
460
|
}
|
|
461
461
|
if (preview.isError) return { block: true, reason: preview.text };
|
|
462
|
+
if (isEmptyPreview(preview.data)) {
|
|
463
|
+
return {
|
|
464
|
+
block: true,
|
|
465
|
+
reason: `Nothing to apply: the preview changes no item, so ${user} was not asked. Tell ${user} why in plain words; do not call ${name} again with the same input. Preview: ${JSON.stringify(preview.data).slice(0, 2000)}`,
|
|
466
|
+
};
|
|
467
|
+
}
|
|
462
468
|
const title = L(`Sub-Sub: apply ${name.replace(/^(zotero|scholar)_/, "")}?`, `Sub-Sub: aplicar ${name.replace(/^(zotero|scholar)_/, "")}?`);
|
|
463
469
|
let shown = formatPreview(name, preview.data ?? preview.text, lang);
|
|
464
470
|
// The dialog may stay open for minutes. Before applying, compute the preview again: if the
|