@plannotator/pi-extension 0.28.37 → 0.28.38
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/generated/guide-viewer-manifest.ts +2 -2
- package/generated/project.ts +3 -2
- package/generated/update-check.ts +60 -8
- package/package.json +1 -1
- package/plannotator.html +452 -451
- package/review-editor.html +410 -409
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
import type { GuideViewerAssets } from "./guide-format.ts";
|
|
7
7
|
|
|
8
8
|
export const GUIDE_VIEWER_MANIFEST: Omit<GuideViewerAssets, "baseUrl"> = {
|
|
9
|
-
js: "viewer.
|
|
9
|
+
js: "viewer.BqcO9v_d.js",
|
|
10
10
|
css: "viewer.DejL7_DK.css",
|
|
11
|
-
jsIntegrity: "sha384-
|
|
11
|
+
jsIntegrity: "sha384-hv0Y+2gJFlY9p99fic5BMf0H8suh2cpCqppFI1GPYYBfCbMLs/4fTmf3astg5o8b",
|
|
12
12
|
cssIntegrity: "sha384-RC1v6OjikD4krGxtTP5dn1SNTtuT4wQWdRSS5HSVrmAdJk97gNs5wbKca+3/0Hdl",
|
|
13
13
|
langs: {
|
|
14
14
|
"astro": "chunks/astro.Ts5EKq2l.js",
|
package/generated/project.ts
CHANGED
|
@@ -22,8 +22,9 @@ export function sanitizeTag(name: string): string | null {
|
|
|
22
22
|
.replace(/[\s_]+/g, "-") // spaces/underscores -> hyphens
|
|
23
23
|
.replace(/[^a-z0-9-]/g, "") // remove special chars
|
|
24
24
|
.replace(/-+/g, "-") // collapse multiple hyphens
|
|
25
|
-
.replace(
|
|
26
|
-
.slice(0, 30)
|
|
25
|
+
.replace(/^-/, "") // trim leading hyphen
|
|
26
|
+
.slice(0, 30) // max 30 chars
|
|
27
|
+
.replace(/-$/, ""); // trim trailing hyphen, after the cut so the result is idempotent
|
|
27
28
|
|
|
28
29
|
return sanitized.length >= 2 ? sanitized : null;
|
|
29
30
|
}
|
|
@@ -84,6 +84,15 @@ const RELEASE_CHECK_TIMEOUT_MS = 8_000;
|
|
|
84
84
|
*/
|
|
85
85
|
export const RELEASE_ASSETS_FETCH_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
86
86
|
export const RELEASE_ASSETS_FETCH_RETRY_MS = 6 * 60 * 60 * 1000;
|
|
87
|
+
/**
|
|
88
|
+
* A release's notes answered with no "What's New" part while the release is
|
|
89
|
+
* young (published under RELEASE_NOTES_YOUNG_MS ago): GitHub's generated
|
|
90
|
+
* body, read in the minutes before the written notes replaced it. Asked again
|
|
91
|
+
* after this instead of RELEASE_ASSETS_FETCH_INTERVAL_MS, so the "What's new"
|
|
92
|
+
* link shows within the hour, not a day later.
|
|
93
|
+
*/
|
|
94
|
+
export const RELEASE_NOTES_PENDING_RETRY_MS = 15 * 60 * 1000;
|
|
95
|
+
export const RELEASE_NOTES_YOUNG_MS = 2 * 24 * 60 * 60 * 1000;
|
|
87
96
|
/** "Remind me tomorrow" in the Inbox. */
|
|
88
97
|
export const UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1000;
|
|
89
98
|
/** The terminal hint shows at most this often. */
|
|
@@ -145,6 +154,19 @@ export function releaseUrlFor(version: string): string {
|
|
|
145
154
|
// State (update-state.json, shared with auto-update)
|
|
146
155
|
// ---------------------------------------------------------------------------
|
|
147
156
|
|
|
157
|
+
/** One version's notes fetch (`notesFetch[<version>]`). */
|
|
158
|
+
export interface NotesFetchRecord {
|
|
159
|
+
attemptedAt: number;
|
|
160
|
+
failedAt?: number;
|
|
161
|
+
error?: string;
|
|
162
|
+
/**
|
|
163
|
+
* The release's `published_at` (epoch ms), kept when its answer carried no
|
|
164
|
+
* "What's New" part: while it is under RELEASE_NOTES_YOUNG_MS old, the next
|
|
165
|
+
* try waits RELEASE_NOTES_PENDING_RETRY_MS instead of a day.
|
|
166
|
+
*/
|
|
167
|
+
publishedAt?: number;
|
|
168
|
+
}
|
|
169
|
+
|
|
148
170
|
export interface UpdateState {
|
|
149
171
|
/** Auto-update's install window (epoch ms of the last check that got past its gates). */
|
|
150
172
|
lastCheckAt?: number;
|
|
@@ -221,7 +243,7 @@ export interface UpdateState {
|
|
|
221
243
|
* One release's notes fetched by its tag (fetchReleaseNotesFor), per
|
|
222
244
|
* version: claimed before the request, so concurrent processes ask once.
|
|
223
245
|
*/
|
|
224
|
-
notesFetch?: Record<string,
|
|
246
|
+
notesFetch?: Record<string, NotesFetchRecord>;
|
|
225
247
|
/**
|
|
226
248
|
* The Inbox's fetch of one release's images (packages/server/inbox-whats-new-images.ts),
|
|
227
249
|
* per version, with the same claim and back-off as `notesFetch`. Only the
|
|
@@ -1045,17 +1067,28 @@ export function scheduleReleaseCheck(deps: ReleaseCheckDeps, then?: (outcome: Re
|
|
|
1045
1067
|
/** How many versions `notesFetch` remembers. */
|
|
1046
1068
|
const NOTES_FETCH_REMEMBERED = 10;
|
|
1047
1069
|
|
|
1070
|
+
/** The record names a release young enough for the quick retry (a clock far off either way does not). */
|
|
1071
|
+
function isYoungRelease(record: NotesFetchRecord, now: number): boolean {
|
|
1072
|
+
const published = record.publishedAt;
|
|
1073
|
+
return typeof published === "number" && Number.isFinite(published) && Math.abs(now - published) < RELEASE_NOTES_YOUNG_MS;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1048
1076
|
/**
|
|
1049
1077
|
* Whether one version's notes may be asked for now: once, then after a
|
|
1050
1078
|
* failure no sooner than 6 h, and after an answer that carried no "What's
|
|
1051
|
-
* New" part no sooner than
|
|
1052
|
-
* Never in a loop.
|
|
1079
|
+
* New" part no sooner than 15 minutes while the release is under 2 days old
|
|
1080
|
+
* (the release body is edited after publishing), else 24 h. Never in a loop.
|
|
1053
1081
|
*/
|
|
1054
1082
|
export function isNotesFetchDue(state: UpdateState, version: string, now: number): boolean {
|
|
1055
1083
|
const record = state.notesFetch?.[version];
|
|
1056
1084
|
const at = record?.attemptedAt;
|
|
1057
1085
|
if (!record || typeof at !== "number" || !Number.isFinite(at) || at > now) return true;
|
|
1058
|
-
|
|
1086
|
+
const wait = record.failedAt
|
|
1087
|
+
? RELEASE_ASSETS_FETCH_RETRY_MS
|
|
1088
|
+
: isYoungRelease(record, now)
|
|
1089
|
+
? RELEASE_NOTES_PENDING_RETRY_MS
|
|
1090
|
+
: RELEASE_ASSETS_FETCH_INTERVAL_MS;
|
|
1091
|
+
return now - at >= wait;
|
|
1059
1092
|
}
|
|
1060
1093
|
|
|
1061
1094
|
export interface ReleaseNotesFetchDeps {
|
|
@@ -1088,7 +1121,7 @@ export async function fetchReleaseNotesFor(deps: ReleaseNotesFetchDeps): Promise
|
|
|
1088
1121
|
if (hasReleaseNotesContent(stored)) return { outcome: "present", notes: stored };
|
|
1089
1122
|
if (!deps.enabled()) return { outcome: "disabled" };
|
|
1090
1123
|
const now = (deps.now ?? Date.now)();
|
|
1091
|
-
const record = (patch:
|
|
1124
|
+
const record = (patch: NotesFetchRecord) =>
|
|
1092
1125
|
patchUpdateState((s) => {
|
|
1093
1126
|
const entries = Object.entries({ ...(s.notesFetch ?? {}), [version]: patch })
|
|
1094
1127
|
.filter(([, r]) => r && typeof r.attemptedAt === "number")
|
|
@@ -1096,10 +1129,16 @@ export async function fetchReleaseNotesFor(deps: ReleaseNotesFetchDeps): Promise
|
|
|
1096
1129
|
.slice(0, NOTES_FETCH_REMEMBERED);
|
|
1097
1130
|
return { ...s, notesFetch: Object.fromEntries(entries) };
|
|
1098
1131
|
}, dataDir);
|
|
1132
|
+
let pendingBefore = false;
|
|
1099
1133
|
try {
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1134
|
+
const state = readUpdateState(dataDir);
|
|
1135
|
+
if (!isNotesFetchDue(state, version, now)) return { outcome: "not-due" };
|
|
1136
|
+
// Claim the attempt before the network call so concurrent processes ask
|
|
1137
|
+
// once. A young release's date is kept, so an attempt that never finished
|
|
1138
|
+
// (the process quit) is tried again on the quick cadence, not in a day.
|
|
1139
|
+
const previous = state.notesFetch?.[version];
|
|
1140
|
+
pendingBefore = !!previous && !previous.failedAt && isYoungRelease(previous, now);
|
|
1141
|
+
record({ attemptedAt: now, ...(pendingBefore && { publishedAt: previous!.publishedAt }) });
|
|
1103
1142
|
} catch (err) {
|
|
1104
1143
|
const error = err instanceof Error ? err.message : String(err);
|
|
1105
1144
|
updateLog(`could not write update-state.json: ${error}`, dataDir);
|
|
@@ -1123,6 +1162,19 @@ export async function fetchReleaseNotesFor(deps: ReleaseNotesFetchDeps): Promise
|
|
|
1123
1162
|
} catch (err) {
|
|
1124
1163
|
updateLog(`could not save the release notes: ${err instanceof Error ? err.message : String(err)}`, dataDir);
|
|
1125
1164
|
}
|
|
1165
|
+
if (!notes) {
|
|
1166
|
+
// GitHub's generated body, read before the written notes replaced it (or
|
|
1167
|
+
// a release with none): a young release is asked again in 15 minutes.
|
|
1168
|
+
const published = release.publishedAt ? Date.parse(release.publishedAt) : NaN;
|
|
1169
|
+
const pending: NotesFetchRecord = { attemptedAt: now, ...(Number.isFinite(published) && { publishedAt: published }) };
|
|
1170
|
+
try {
|
|
1171
|
+
record(pending);
|
|
1172
|
+
} catch {}
|
|
1173
|
+
// One line per version, not one per retry.
|
|
1174
|
+
if (isYoungRelease(pending, now) && !pendingBefore) {
|
|
1175
|
+
updateLog(`the release notes for ${version} have no "What's New" part yet; next try in ${formatWait(RELEASE_NOTES_PENDING_RETRY_MS)}`, dataDir);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1126
1178
|
// The release page names no publish date: take this answer's for the latest release.
|
|
1127
1179
|
if (release.publishedAt) {
|
|
1128
1180
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plannotator/pi-extension",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.38",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Plannotator Pi extension - interactive plan review with annotations, annotate agent messages, and review code/PRs",
|
|
6
6
|
"author": "backnotprop",
|