@plannotator/pi-extension 0.28.38 → 0.28.40
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/ai/providers/ask-ai-env.ts +217 -0
- package/generated/ai/providers/claude-agent-sdk.ts +19 -0
- package/generated/ai/providers/codex-app-server.ts +13 -5
- package/generated/ai/providers/opencode-sdk.ts +13 -5
- package/generated/ai/providers/pi-events.ts +1 -1
- package/generated/ai/providers/pi-sdk-node.ts +5 -0
- package/generated/ai/providers/pi-sdk.ts +6 -2
- package/generated/ai/providers/qwen-sdk.ts +5 -1
- package/generated/call-flow-languages.ts +4 -2
- package/generated/call-flow-runtime/package-lock.json +7 -7
- package/generated/call-flow-runtime/package.json +2 -2
- package/generated/call-flow.ts +149 -32
- package/generated/child-env.ts +12 -0
- package/generated/claude-review.ts +3 -0
- package/generated/codex-review.ts +3 -0
- package/generated/guide-review.ts +3 -0
- package/generated/guide-viewer-manifest.ts +4 -4
- package/generated/inbox/connection.ts +59 -16
- package/generated/question-block.ts +2 -2
- package/generated/tour-review.ts +3 -0
- package/generated/update-check.ts +62 -15
- package/package.json +1 -1
- package/plannotator.html +85 -85
- package/review-editor.html +422 -397
- package/server/agent-jobs-ask-ai-child.test.ts +149 -0
- package/server/agent-jobs.ts +5 -1
- package/server/serverReview.ts +4 -0
- package/skills/plannotator/SKILL.md +3 -3
|
@@ -165,6 +165,21 @@ export interface NotesFetchRecord {
|
|
|
165
165
|
* try waits RELEASE_NOTES_PENDING_RETRY_MS instead of a day.
|
|
166
166
|
*/
|
|
167
167
|
publishedAt?: number;
|
|
168
|
+
/**
|
|
169
|
+
* Set on the claim, gone once GitHub answers: a claim still marked was
|
|
170
|
+
* abandoned (its process quit mid-request), and is asked again after
|
|
171
|
+
* RELEASE_NOTES_PENDING_RETRY_MS, not read as an empty answer (24 h).
|
|
172
|
+
*/
|
|
173
|
+
inFlight?: boolean;
|
|
174
|
+
/**
|
|
175
|
+
* Set on a failure that may have been the network (not a rate limit, and
|
|
176
|
+
* no release check answered between the failure before it and this one):
|
|
177
|
+
* asked again RELEASE_NOTES_PENDING_RETRY_MS after it once a release check
|
|
178
|
+
* has answered since (the network is back), not after 6 h. One quick retry,
|
|
179
|
+
* then 6 h: a source that keeps failing while the network is up (or a
|
|
180
|
+
* network that drops again before the quick retry) waits 6 h.
|
|
181
|
+
*/
|
|
182
|
+
retryOnline?: boolean;
|
|
168
183
|
}
|
|
169
184
|
|
|
170
185
|
export interface UpdateState {
|
|
@@ -239,6 +254,13 @@ export interface UpdateState {
|
|
|
239
254
|
* skipped from it, so "Also in the releases since X" survives the update.
|
|
240
255
|
*/
|
|
241
256
|
inboxPreviousVersion?: string;
|
|
257
|
+
/**
|
|
258
|
+
* The version an Inbox start found newer than `inboxVersion`, kept until its
|
|
259
|
+
* "What's new" link was offered with readable notes: a start on that same
|
|
260
|
+
* version shows the link too, so a restart before the notes were readable
|
|
261
|
+
* does not lose it.
|
|
262
|
+
*/
|
|
263
|
+
whatsNewPending?: string;
|
|
242
264
|
/**
|
|
243
265
|
* One release's notes fetched by its tag (fetchReleaseNotesFor), per
|
|
244
266
|
* version: claimed before the request, so concurrent processes ask once.
|
|
@@ -246,10 +268,10 @@ export interface UpdateState {
|
|
|
246
268
|
notesFetch?: Record<string, NotesFetchRecord>;
|
|
247
269
|
/**
|
|
248
270
|
* The Inbox's fetch of one release's images (packages/server/inbox-whats-new-images.ts),
|
|
249
|
-
* per version, with the same claim and back-off as `notesFetch
|
|
250
|
-
* Inbox writes it; nothing here fetches an image.
|
|
271
|
+
* per version, with the same claim and back-off as `notesFetch` (its
|
|
272
|
+
* `inFlight` mark too). Only the Inbox writes it; nothing here fetches an image.
|
|
251
273
|
*/
|
|
252
|
-
releaseImagesFetch?: Record<string,
|
|
274
|
+
releaseImagesFetch?: Record<string, Pick<NotesFetchRecord, "attemptedAt" | "failedAt" | "error" | "inFlight">>;
|
|
253
275
|
/**
|
|
254
276
|
* Safe updates: installs of `version` whose download did not match the
|
|
255
277
|
* checksum Plannotator fetched (install.sh exit 113), counted once each.
|
|
@@ -1073,19 +1095,32 @@ function isYoungRelease(record: NotesFetchRecord, now: number): boolean {
|
|
|
1073
1095
|
return typeof published === "number" && Number.isFinite(published) && Math.abs(now - published) < RELEASE_NOTES_YOUNG_MS;
|
|
1074
1096
|
}
|
|
1075
1097
|
|
|
1098
|
+
/**
|
|
1099
|
+
* A release check answered after `at` (the network is up again since then).
|
|
1100
|
+
* An answer dated after `now` (the clock moved back) does not count.
|
|
1101
|
+
*/
|
|
1102
|
+
function releaseCheckAnsweredAfter(state: UpdateState, at: number, now: number): boolean {
|
|
1103
|
+
const answered = state.latestRelease?.fetchedAt;
|
|
1104
|
+
return typeof answered === "number" && answered > at && answered <= now;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1076
1107
|
/**
|
|
1077
1108
|
* Whether one version's notes may be asked for now: once, then after a
|
|
1078
|
-
* failure no sooner than 6 h
|
|
1079
|
-
*
|
|
1080
|
-
*
|
|
1109
|
+
* failure no sooner than 6 h (15 minutes once the network is back, see
|
|
1110
|
+
* `retryOnline`), after an answer that carried no "What's New" part no
|
|
1111
|
+
* sooner than 15 minutes while the release is under 2 days old (the release
|
|
1112
|
+
* body is edited after publishing), else 24 h. A claim nobody answered (its
|
|
1113
|
+
* process quit) waits 15 minutes. Never sooner than 15 minutes, never in a loop.
|
|
1081
1114
|
*/
|
|
1082
1115
|
export function isNotesFetchDue(state: UpdateState, version: string, now: number): boolean {
|
|
1083
1116
|
const record = state.notesFetch?.[version];
|
|
1084
1117
|
const at = record?.attemptedAt;
|
|
1085
1118
|
if (!record || typeof at !== "number" || !Number.isFinite(at) || at > now) return true;
|
|
1086
1119
|
const wait = record.failedAt
|
|
1087
|
-
?
|
|
1088
|
-
|
|
1120
|
+
? record.retryOnline && releaseCheckAnsweredAfter(state, record.failedAt, now)
|
|
1121
|
+
? RELEASE_NOTES_PENDING_RETRY_MS
|
|
1122
|
+
: RELEASE_ASSETS_FETCH_RETRY_MS
|
|
1123
|
+
: record.inFlight || isYoungRelease(record, now)
|
|
1089
1124
|
? RELEASE_NOTES_PENDING_RETRY_MS
|
|
1090
1125
|
: RELEASE_ASSETS_FETCH_INTERVAL_MS;
|
|
1091
1126
|
return now - at >= wait;
|
|
@@ -1130,15 +1165,17 @@ export async function fetchReleaseNotesFor(deps: ReleaseNotesFetchDeps): Promise
|
|
|
1130
1165
|
return { ...s, notesFetch: Object.fromEntries(entries) };
|
|
1131
1166
|
}, dataDir);
|
|
1132
1167
|
let pendingBefore = false;
|
|
1168
|
+
let previous: NotesFetchRecord | undefined;
|
|
1169
|
+
let state: UpdateState;
|
|
1133
1170
|
try {
|
|
1134
|
-
|
|
1171
|
+
state = readUpdateState(dataDir);
|
|
1135
1172
|
if (!isNotesFetchDue(state, version, now)) return { outcome: "not-due" };
|
|
1136
1173
|
// Claim the attempt before the network call so concurrent processes ask
|
|
1137
|
-
// once.
|
|
1138
|
-
//
|
|
1139
|
-
|
|
1174
|
+
// once. Marked in flight, so an attempt that never finished (the process
|
|
1175
|
+
// quit) is tried again on the quick cadence, not in a day.
|
|
1176
|
+
previous = state.notesFetch?.[version];
|
|
1140
1177
|
pendingBefore = !!previous && !previous.failedAt && isYoungRelease(previous, now);
|
|
1141
|
-
record({ attemptedAt: now, ...(pendingBefore && { publishedAt: previous!.publishedAt }) });
|
|
1178
|
+
record({ attemptedAt: now, inFlight: true, ...(pendingBefore && { publishedAt: previous!.publishedAt }) });
|
|
1142
1179
|
} catch (err) {
|
|
1143
1180
|
const error = err instanceof Error ? err.message : String(err);
|
|
1144
1181
|
updateLog(`could not write update-state.json: ${error}`, dataDir);
|
|
@@ -1148,9 +1185,14 @@ export async function fetchReleaseNotesFor(deps: ReleaseNotesFetchDeps): Promise
|
|
|
1148
1185
|
const tag = result.ok ? normalizeStableVersion(result.release.tag) : null;
|
|
1149
1186
|
if (!result.ok || tag !== version) {
|
|
1150
1187
|
const error = result.ok ? `the release answered for ${JSON.stringify(result.release.tag).slice(0, 80)}` : result.error;
|
|
1151
|
-
|
|
1188
|
+
// Maybe the network (a laptop waking, a VPN): asked again 15 minutes after,
|
|
1189
|
+
// once a release check answers. Not after a rate limit, and not when this
|
|
1190
|
+
// source failed before with a release check answering since (it keeps
|
|
1191
|
+
// failing while the network is up: 6 h).
|
|
1192
|
+
const retryOnline = !(!result.ok && result.rateLimited) && !(previous?.failedAt && releaseCheckAnsweredAfter(state, previous.failedAt, now));
|
|
1193
|
+
updateLog(`could not read the release notes for ${version} (${error}); next try in ${retryOnline ? "15m once online, else 6h" : "6h"}`, dataDir);
|
|
1152
1194
|
try {
|
|
1153
|
-
record({ attemptedAt: now, failedAt: now, error: error.slice(0, 200) });
|
|
1195
|
+
record({ attemptedAt: now, failedAt: now, error: error.slice(0, 200), ...(retryOnline && { retryOnline }) });
|
|
1154
1196
|
} catch {}
|
|
1155
1197
|
return { outcome: "failed", error };
|
|
1156
1198
|
}
|
|
@@ -1174,6 +1216,11 @@ export async function fetchReleaseNotesFor(deps: ReleaseNotesFetchDeps): Promise
|
|
|
1174
1216
|
if (isYoungRelease(pending, now) && !pendingBefore) {
|
|
1175
1217
|
updateLog(`the release notes for ${version} have no "What's New" part yet; next try in ${formatWait(RELEASE_NOTES_PENDING_RETRY_MS)}`, dataDir);
|
|
1176
1218
|
}
|
|
1219
|
+
} else {
|
|
1220
|
+
// Answered: no longer in flight (it matters only when the notes could not be saved).
|
|
1221
|
+
try {
|
|
1222
|
+
record({ attemptedAt: now });
|
|
1223
|
+
} catch {}
|
|
1177
1224
|
}
|
|
1178
1225
|
// The release page names no publish date: take this answer's for the latest release.
|
|
1179
1226
|
if (release.publishedAt) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plannotator/pi-extension",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.40",
|
|
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",
|