@caseyharalson/orrery 0.7.1 → 0.8.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.
@@ -85,31 +85,23 @@ ${getFormatInstructions()}
85
85
  - Complete each step fully before starting the next
86
86
  - Output clean JSON to stdout—no extra text or markdown wrapping`;
87
87
 
88
- const REVIEW_PROMPT = `You are a Review Agent. Evaluate the changes for the completed plan step.
88
+ const REVIEW_PROMPT = `You are a Review Agent. Review the completed plan step.
89
89
 
90
- ## Context
91
-
92
- Step context:
93
- {stepContext}
94
-
95
- Modified files:
96
- {files}
97
-
98
- Diff:
99
- {diff}
90
+ Plan file: {planFile}
91
+ Step to review: {stepIds}
100
92
 
101
- ## Instructions
93
+ ## Workflow
102
94
 
103
- - Identify bugs, regressions, missing edge cases, or unmet acceptance criteria.
104
- - If changes are acceptable, respond with approval.
105
- - If changes need edits, provide specific, actionable feedback.
106
- - Keep feedback concise and grounded in the diff.
95
+ 1. Read the plan file to understand the step's description, requirements, and acceptance criteria
96
+ 2. Run \`git diff\` to see all uncommitted changes
97
+ 3. Read modified files for full context if needed
98
+ 4. Evaluate if changes correctly implement the requirements
107
99
 
108
- ## Output Format (JSON, single line)
100
+ ## Output Format (JSON)
109
101
 
110
102
  {"status":"approved","summary":"..."}
111
103
  OR
112
- {"status":"changes_requested","summary":"...","comments":["...","..."]}`;
104
+ {"status":"needs_changes","feedback":[{"comment":"...","file":"...","severity":"blocking|suggestion"}]}`;
113
105
 
114
106
  module.exports = {
115
107
  // Agent configurations (keyed by agent name)
@@ -49,8 +49,7 @@ const {
49
49
  commit,
50
50
  createPullRequest,
51
51
  deriveBranchName,
52
- hasUncommittedChanges,
53
- getUncommittedDiff
52
+ hasUncommittedChanges
54
53
  } = require("../utils/git");
55
54
 
56
55
  const config = require("./config");
@@ -832,8 +831,6 @@ async function waitForAgentCompletion(
832
831
  // Parse results from stdout
833
832
  let parsedResults = parseAgentResults(result.stdout);
834
833
 
835
- const planForReview = loadPlan(planFile);
836
-
837
834
  // Build updates for each step
838
835
  const updates = [];
839
836
  const reports = [];
@@ -852,51 +849,25 @@ async function waitForAgentCompletion(
852
849
  stepResult = createDefaultResult(stepId, result.exitCode, result.stderr);
853
850
  }
854
851
 
852
+ let stepReviews = null;
855
853
  if (config.review.enabled && stepResult.status === "complete") {
856
854
  const maxIterations = resolveReviewMaxIterations();
857
855
  if (maxIterations > 0) {
858
- const stepData =
859
- (planForReview.steps || []).find((step) => step.id === stepId) ||
860
- null;
861
- const stepContext = stepData
862
- ? {
863
- id: stepData.id,
864
- description: stepData.description,
865
- context: stepData.context,
866
- requirements: stepData.requirements,
867
- criteria: stepData.criteria,
868
- files: stepData.files,
869
- risk_notes: stepData.risk_notes
870
- }
871
- : `Step ${stepId} context not found.`;
872
-
873
856
  let approved = false;
874
857
  let currentResult = stepResult;
858
+ const reviews = [];
859
+ stepReviews = reviews;
875
860
 
876
861
  for (let iteration = 1; iteration <= maxIterations; iteration++) {
877
- const files =
878
- Array.isArray(currentResult.artifacts) &&
879
- currentResult.artifacts.length > 0
880
- ? currentResult.artifacts
881
- : stepData && Array.isArray(stepData.files)
882
- ? stepData.files
883
- : [];
884
- const diff = getUncommittedDiff(REPO_ROOT, files);
885
-
886
862
  console.log(
887
863
  `Review iteration ${iteration}/${maxIterations} for step ${stepId}`
888
864
  );
889
865
  const reviewResult = await invokeReviewAgent(
890
866
  config,
891
- stepContext,
892
- files,
893
- diff,
867
+ tempPlanFile,
868
+ [stepId],
894
869
  REPO_ROOT,
895
- {
896
- planFile,
897
- stepId,
898
- stepIds: [stepId]
899
- }
870
+ { stepId }
900
871
  );
901
872
 
902
873
  if (reviewResult.error) {
@@ -907,6 +878,11 @@ async function waitForAgentCompletion(
907
878
 
908
879
  if (reviewResult.approved) {
909
880
  console.log(`Review approved for step ${stepId}`);
881
+ reviews.push({
882
+ iteration,
883
+ approved: true,
884
+ feedback: []
885
+ });
910
886
  approved = true;
911
887
  break;
912
888
  }
@@ -916,6 +892,26 @@ async function waitForAgentCompletion(
916
892
  `Review needs changes for step ${stepId}: ${issueCount} issue(s)`
917
893
  );
918
894
 
895
+ for (const fb of reviewResult.feedback) {
896
+ const loc = fb.file
897
+ ? ` ${fb.file}${fb.line ? `:${fb.line}` : ""}`
898
+ : "";
899
+ const sev =
900
+ fb.severity === "blocking" ? "[blocking]" : "[suggestion]";
901
+ console.log(` ${sev}${loc}: ${fb.comment}`);
902
+ }
903
+
904
+ reviews.push({
905
+ iteration,
906
+ approved: false,
907
+ feedback: reviewResult.feedback.map((fb) => ({
908
+ severity: fb.severity,
909
+ file: fb.file || null,
910
+ line: fb.line || null,
911
+ comment: fb.comment
912
+ }))
913
+ });
914
+
919
915
  if (iteration >= maxIterations) {
920
916
  break;
921
917
  }
@@ -970,7 +966,7 @@ async function waitForAgentCompletion(
970
966
  updates.push(update);
971
967
 
972
968
  // Prepare report
973
- reports.push({
969
+ const reportData = {
974
970
  step_id: stepId,
975
971
  agent: agentName,
976
972
  outcome: stepResult.status === "complete" ? "success" : "failure",
@@ -979,7 +975,11 @@ async function waitForAgentCompletion(
979
975
  artifacts: stepResult.artifacts || [],
980
976
  blocked_reason: stepResult.blockedReason || null,
981
977
  test_results: stepResult.testResults || null
982
- });
978
+ };
979
+ if (stepReviews) {
980
+ reportData.reviews = stepReviews;
981
+ }
982
+ reports.push(reportData);
983
983
  }
984
984
 
985
985
  // Update plan file
@@ -1,57 +1,13 @@
1
1
  const { invokeAgentWithFailover } = require("./agent-invoker");
2
2
 
3
- function formatStepContext(stepContext) {
4
- if (stepContext === undefined || stepContext === null) {
5
- return "(no step context provided)";
6
- }
7
-
8
- if (typeof stepContext === "string") {
9
- const trimmed = stepContext.trim();
10
- return trimmed.length > 0 ? trimmed : "(no step context provided)";
11
- }
12
-
13
- try {
14
- return JSON.stringify(stepContext, null, 2);
15
- } catch {
16
- return String(stepContext);
17
- }
18
- }
19
-
20
- function formatFiles(files) {
21
- if (!files) {
22
- return "(no files provided)";
23
- }
24
-
25
- if (Array.isArray(files)) {
26
- if (files.length === 0) {
27
- return "(no files provided)";
28
- }
29
- return files.map((file) => `- ${file}`).join("\n");
30
- }
31
-
32
- const trimmed = String(files).trim();
33
- return trimmed.length > 0 ? trimmed : "(no files provided)";
34
- }
35
-
36
- function ensureFullFileInstruction(prompt) {
37
- const fullFileRegex = /full file|full files|full contents/i;
38
- if (fullFileRegex.test(prompt)) {
39
- return prompt;
40
- }
41
-
42
- const instruction =
43
- "Read the full contents of each modified file for context, not only the diff.";
44
- return `${prompt}\n\n## Required Context\n${instruction}`;
45
- }
46
-
47
- function buildReviewPrompt(template, stepContext, files, diff) {
3
+ function buildReviewPrompt(template, planFile, stepIds) {
48
4
  const basePrompt = String(template || "");
49
- const promptWithContext = basePrompt
50
- .replace("{stepContext}", formatStepContext(stepContext))
51
- .replace("{files}", formatFiles(files))
52
- .replace("{diff}", diff ? String(diff) : "(no diff provided)");
53
-
54
- return ensureFullFileInstruction(promptWithContext);
5
+ const stepIdsStr = Array.isArray(stepIds)
6
+ ? stepIds.join(", ")
7
+ : String(stepIds);
8
+ return basePrompt
9
+ .replace("{planFile}", planFile || "")
10
+ .replace("{stepIds}", stepIdsStr);
55
11
  }
56
12
 
57
13
  function buildReviewConfig(config, prompt) {
@@ -268,9 +224,8 @@ function parseReviewResults(stdout) {
268
224
 
269
225
  async function invokeReviewAgent(
270
226
  config,
271
- stepContext,
272
- files,
273
- diff,
227
+ planFile,
228
+ stepIds,
274
229
  repoRoot,
275
230
  options = {}
276
231
  ) {
@@ -278,19 +233,14 @@ async function invokeReviewAgent(
278
233
  (config && config.review && config.review.prompt) ||
279
234
  config.REVIEW_PROMPT ||
280
235
  "";
281
- const prompt = buildReviewPrompt(promptTemplate, stepContext, files, diff);
236
+ const normalizedStepIds = Array.isArray(stepIds) ? stepIds : [stepIds];
237
+ const prompt = buildReviewPrompt(promptTemplate, planFile, normalizedStepIds);
282
238
  const reviewConfig = buildReviewConfig(config, prompt);
283
- const planFile = options.planFile || options.planPath || "review";
284
- const stepIds = options.stepIds
285
- ? options.stepIds
286
- : options.stepId
287
- ? [options.stepId]
288
- : ["review"];
289
239
 
290
240
  const handle = invokeAgentWithFailover(
291
241
  reviewConfig,
292
242
  planFile,
293
- stepIds,
243
+ normalizedStepIds,
294
244
  repoRoot,
295
245
  options
296
246
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caseyharalson/orrery",
3
- "version": "0.7.1",
3
+ "version": "0.8.0",
4
4
  "description": "Workflow planning and orchestration CLI for AI agents",
5
5
  "license": "MIT",
6
6
  "author": "Casey Haralson",