iterate-plugin 2.9.0 → 2.9.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.
@@ -90,7 +90,7 @@ for (let r = 1; r <= maxRounds; r++) {
90
90
  : ''
91
91
  const raw = await parallel(dims.map(dim => () => agent(
92
92
  'Review dimension "' + dim + '".' +
93
- (attachments.length > 0 ? ' User-attached images are part of the evidence (reproduce/verify against them): ' + JSON.stringify(attachments) + '.' : '') +
93
+ (attachments.length > 0 ? ' User-attached images are part of the evidence; use their descriptions when judging (you see the metadata/descriptions below, not the pixels): ' + JSON.stringify(attachments) + '.' : '') +
94
94
  ' Already-known findings (do NOT re-report): ' +
95
95
  JSON.stringify(known) + nudge + '\\nReturn the findings JSON object.',
96
96
  Object.assign({ label: 'review:' + dim + ':r' + r, schema: plan.dimensions.find(x => x.id === dim).findingsSchema }, backend)
@@ -190,11 +190,13 @@ const checkpoint = (ckRes && ckRes.checkpoint) ? ckRes.checkpoint : null
190
190
  const startRound = (checkpoint && typeof checkpoint.round === 'number') ? checkpoint.round + 1 : 1
191
191
  // Track how many times this checkpoint has already been resumed (interruption recovery).
192
192
  const resumeCount = (checkpoint && typeof checkpoint.resumeCount === 'number') ? checkpoint.resumeCount : 0
193
+ // The effective count AFTER this recovery: this run counts as one more resume.
194
+ const effectiveResumeCount = checkpoint ? resumeCount + 1 : 0
193
195
  if (checkpoint) {
194
196
  // A previous run left a checkpoint — record the recovery so the decision log
195
197
  // shows the resume, then continue where it left off.
196
198
  await agent(
197
- 'Call iterate_decision_log({operation:"append", type:"resume", round:' + startRound + ', data:{resumedFromRound:' + checkpoint.round + ', resumeCount:' + (resumeCount + 1) + '}})',
199
+ 'Call iterate_decision_log({operation:"append", type:"resume", round:' + startRound + ', data:{resumedFromRound:' + checkpoint.round + ', resumeCount:' + effectiveResumeCount + '}})',
198
200
  Object.assign({ label: 'log:resume' }, backend)
199
201
  )
200
202
  }
@@ -216,7 +218,8 @@ const knownIntentional = (plan.knownIntentional || []) // config personalizati
216
218
  const dims = plan.dimensions.map(d => d.id)
217
219
  const maxRounds = plan.maxReviewRounds
218
220
  const rounds = [] // findings per review round (each on the then-current code state)
219
- const architectural = [] // findings deliberately left unfixed (reported at the end)
221
+ // Restore previously-unfixed architectural findings when resuming an interrupted run.
222
+ const architectural = (checkpoint && Array.isArray(checkpoint.findings)) ? checkpoint.findings : [] // findings deliberately left unfixed (reported at the end)
220
223
  let fixedCount = (checkpoint && typeof checkpoint.fixedCount === 'number') ? checkpoint.fixedCount : 0
221
224
  let converged = false
222
225
  let abortedByValidation = false
@@ -235,7 +238,7 @@ for (let r = startRound; r <= maxRounds; r++) {
235
238
  : ''
236
239
  const raw = await parallel(dims.map(dim => () => agent(
237
240
  'Review dimension "' + dim + '" on the CURRENT code state (previous atomic findings are fixed). ' +
238
- (attachments.length > 0 ? ' User-attached images are part of the evidence (reproduce/verify against them): ' + JSON.stringify(attachments) + '.' : '') +
241
+ (attachments.length > 0 ? ' User-attached images are part of the evidence; use their descriptions when judging (you see the metadata/descriptions below, not the pixels): ' + JSON.stringify(attachments) + '.' : '') +
239
242
  'Do NOT re-report already-known architectural findings: ' + JSON.stringify(architectural) + nudge + '\\nReturn the findings JSON object.',
240
243
  Object.assign({ label: 'review:' + dim + ':r' + r, schema: plan.dimensions.find(x => x.id === dim).findingsSchema }, backend)
241
244
  )))
@@ -341,7 +344,7 @@ for (let r = startRound; r <= maxRounds; r++) {
341
344
 
342
345
  // Persist progress so an interrupted run can resume from the next round.
343
346
  await agent(
344
- 'Call iterate_checkpoint({ operation: "save", mode: "normal", round:' + r + ', maxRounds:' + maxRounds + ', fixedCount:' + fixedCount + ', architecturalCount:' + architectural.length + ', resumeCount:' + resumeCount + ', findings:' + JSON.stringify(architectural) + ' }) and return the checkpoint JSON.',
347
+ 'Call iterate_checkpoint({ operation: "save", mode: "normal", round:' + r + ', maxRounds:' + maxRounds + ', fixedCount:' + fixedCount + ', architecturalCount:' + architectural.length + ', resumeCount:' + effectiveResumeCount + ', findings:' + JSON.stringify(architectural) + ' }) and return the checkpoint JSON.',
345
348
  Object.assign({ label: 'checkpoint:save:r' + r }, backend)
346
349
  )
347
350
 
@@ -7,6 +7,8 @@ import { resolveProjectRoot } from "../config-loader.js";
7
7
  const MAX_SKILL_DIR_LOOKUP_DEPTH = 12;
8
8
  /** Maximum number of image attachments relayed into the context in one call. */
9
9
  const MAX_ATTACHMENTS = 8;
10
+ /** Maximum intrinsic width/height (px) accepted for an attached image. */
11
+ const MAX_ATTACHMENT_DIMENSION = 16384;
10
12
  /**
11
13
  * Validate and normalize one raw image-attachment entry passed by the
12
14
  * orchestrator. The top-level model observes user-attached images in its own
@@ -33,8 +35,8 @@ export function normalizeAttachment(raw) {
33
35
  }
34
36
  for (const dim of ['width', 'height']) {
35
37
  if (entry[dim] !== undefined) {
36
- if (typeof entry[dim] !== 'number' || !Number.isInteger(entry[dim]) || entry[dim] < 0 || entry[dim] > 16384) {
37
- return { ok: false, error: `attachment.${dim} must be an integer in [0, 16384]` };
38
+ if (typeof entry[dim] !== 'number' || !Number.isInteger(entry[dim]) || entry[dim] < 0 || entry[dim] > MAX_ATTACHMENT_DIMENSION) {
39
+ return { ok: false, error: `attachment.${dim} must be an integer in [0, ${MAX_ATTACHMENT_DIMENSION}]` };
38
40
  }
39
41
  out[dim] = entry[dim];
40
42
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iterate-plugin",
3
- "version": "2.9.0",
3
+ "version": "2.9.1",
4
4
  "description": "dsh plugin that turns the iterate skill into an autonomous closed-loop harness: plan -> parallel review xN -> atomic fixes -> validate -> loop -> auto-stop, plus a dry-run pure-review mode with multi-round convergence and a meta-review that audits the report and emits a final review report.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -91,7 +91,7 @@ for (let r = 1; r <= maxRounds; r++) {
91
91
  : ''
92
92
  const raw = await parallel(dims.map(dim => () => agent(
93
93
  'Review dimension "' + dim + '".' +
94
- (attachments.length > 0 ? ' User-attached images are part of the evidence (reproduce/verify against them): ' + JSON.stringify(attachments) + '.' : '') +
94
+ (attachments.length > 0 ? ' User-attached images are part of the evidence; use their descriptions when judging (you see the metadata/descriptions below, not the pixels): ' + JSON.stringify(attachments) + '.' : '') +
95
95
  ' Already-known findings (do NOT re-report): ' +
96
96
  JSON.stringify(known) + nudge + '\\nReturn the findings JSON object.',
97
97
  Object.assign({ label: 'review:' + dim + ':r' + r, schema: plan.dimensions.find(x => x.id === dim).findingsSchema }, backend)
@@ -191,11 +191,13 @@ const checkpoint = (ckRes && ckRes.checkpoint) ? ckRes.checkpoint : null
191
191
  const startRound = (checkpoint && typeof checkpoint.round === 'number') ? checkpoint.round + 1 : 1
192
192
  // Track how many times this checkpoint has already been resumed (interruption recovery).
193
193
  const resumeCount = (checkpoint && typeof checkpoint.resumeCount === 'number') ? checkpoint.resumeCount : 0
194
+ // The effective count AFTER this recovery: this run counts as one more resume.
195
+ const effectiveResumeCount = checkpoint ? resumeCount + 1 : 0
194
196
  if (checkpoint) {
195
197
  // A previous run left a checkpoint — record the recovery so the decision log
196
198
  // shows the resume, then continue where it left off.
197
199
  await agent(
198
- 'Call iterate_decision_log({operation:"append", type:"resume", round:' + startRound + ', data:{resumedFromRound:' + checkpoint.round + ', resumeCount:' + (resumeCount + 1) + '}})',
200
+ 'Call iterate_decision_log({operation:"append", type:"resume", round:' + startRound + ', data:{resumedFromRound:' + checkpoint.round + ', resumeCount:' + effectiveResumeCount + '}})',
199
201
  Object.assign({ label: 'log:resume' }, backend)
200
202
  )
201
203
  }
@@ -217,7 +219,8 @@ const knownIntentional = (plan.knownIntentional || []) // config personalizati
217
219
  const dims = plan.dimensions.map(d => d.id)
218
220
  const maxRounds = plan.maxReviewRounds
219
221
  const rounds = [] // findings per review round (each on the then-current code state)
220
- const architectural = [] // findings deliberately left unfixed (reported at the end)
222
+ // Restore previously-unfixed architectural findings when resuming an interrupted run.
223
+ const architectural = (checkpoint && Array.isArray(checkpoint.findings)) ? checkpoint.findings : [] // findings deliberately left unfixed (reported at the end)
221
224
  let fixedCount = (checkpoint && typeof checkpoint.fixedCount === 'number') ? checkpoint.fixedCount : 0
222
225
  let converged = false
223
226
  let abortedByValidation = false
@@ -236,7 +239,7 @@ for (let r = startRound; r <= maxRounds; r++) {
236
239
  : ''
237
240
  const raw = await parallel(dims.map(dim => () => agent(
238
241
  'Review dimension "' + dim + '" on the CURRENT code state (previous atomic findings are fixed). ' +
239
- (attachments.length > 0 ? ' User-attached images are part of the evidence (reproduce/verify against them): ' + JSON.stringify(attachments) + '.' : '') +
242
+ (attachments.length > 0 ? ' User-attached images are part of the evidence; use their descriptions when judging (you see the metadata/descriptions below, not the pixels): ' + JSON.stringify(attachments) + '.' : '') +
240
243
  'Do NOT re-report already-known architectural findings: ' + JSON.stringify(architectural) + nudge + '\\nReturn the findings JSON object.',
241
244
  Object.assign({ label: 'review:' + dim + ':r' + r, schema: plan.dimensions.find(x => x.id === dim).findingsSchema }, backend)
242
245
  )))
@@ -342,7 +345,7 @@ for (let r = startRound; r <= maxRounds; r++) {
342
345
 
343
346
  // Persist progress so an interrupted run can resume from the next round.
344
347
  await agent(
345
- 'Call iterate_checkpoint({ operation: "save", mode: "normal", round:' + r + ', maxRounds:' + maxRounds + ', fixedCount:' + fixedCount + ', architecturalCount:' + architectural.length + ', resumeCount:' + resumeCount + ', findings:' + JSON.stringify(architectural) + ' }) and return the checkpoint JSON.',
348
+ 'Call iterate_checkpoint({ operation: "save", mode: "normal", round:' + r + ', maxRounds:' + maxRounds + ', fixedCount:' + fixedCount + ', architecturalCount:' + architectural.length + ', resumeCount:' + effectiveResumeCount + ', findings:' + JSON.stringify(architectural) + ' }) and return the checkpoint JSON.',
346
349
  Object.assign({ label: 'checkpoint:save:r' + r }, backend)
347
350
  )
348
351
 
@@ -10,6 +10,9 @@ const MAX_SKILL_DIR_LOOKUP_DEPTH = 12
10
10
  /** Maximum number of image attachments relayed into the context in one call. */
11
11
  const MAX_ATTACHMENTS = 8
12
12
 
13
+ /** Maximum intrinsic width/height (px) accepted for an attached image. */
14
+ const MAX_ATTACHMENT_DIMENSION = 16384
15
+
13
16
  /** A validated, normalized image-attachment entry carried into review context. */
14
17
  export interface NormalizedAttachment {
15
18
  name?: string
@@ -50,8 +53,8 @@ export function normalizeAttachment(raw: unknown): AttachmentValidationResult {
50
53
  }
51
54
  for (const dim of ['width', 'height'] as const) {
52
55
  if (entry[dim] !== undefined) {
53
- if (typeof entry[dim] !== 'number' || !Number.isInteger(entry[dim]) || entry[dim] < 0 || entry[dim] > 16384) {
54
- return { ok: false, error: `attachment.${dim} must be an integer in [0, 16384]` }
56
+ if (typeof entry[dim] !== 'number' || !Number.isInteger(entry[dim]) || entry[dim] < 0 || entry[dim] > MAX_ATTACHMENT_DIMENSION) {
57
+ return { ok: false, error: `attachment.${dim} must be an integer in [0, ${MAX_ATTACHMENT_DIMENSION}]` }
55
58
  }
56
59
  out[dim] = entry[dim]
57
60
  }