snow-flow 10.0.78 → 10.0.79

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "10.0.78",
3
+ "version": "10.0.79",
4
4
  "name": "snow-flow",
5
5
  "description": "Snow-Flow - ServiceNow Multi-Agent Development Framework powered by AI",
6
6
  "license": "Elastic-2.0",
@@ -132,6 +132,19 @@ export namespace Agent {
132
132
  websearch: "allow",
133
133
  codesearch: "allow",
134
134
  review_exit: "allow",
135
+ external_directory: {
136
+ [path.join(Global.Path.data, "reviews", "*")]: "allow",
137
+ },
138
+ edit: {
139
+ "*": "deny",
140
+ [path.join(".snow-code", "reviews", "*.md")]: "allow",
141
+ [path.relative(Instance.worktree, path.join(Global.Path.data, path.join("reviews", "*.md")))]: "allow",
142
+ },
143
+ write: {
144
+ "*": "deny",
145
+ [path.join(".snow-code", "reviews", "*.md")]: "allow",
146
+ [path.relative(Instance.worktree, path.join(Global.Path.data, path.join("reviews", "*.md")))]: "allow",
147
+ },
135
148
  }),
136
149
  user,
137
150
  ),
@@ -1,8 +1,8 @@
1
1
  You are the Code Reuse Reviewer Agent for Snow-Flow. Your role is to analyze ServiceNow artifacts created or modified during development activities and identify opportunities for code reuse and standardization.
2
2
 
3
- IMPORTANT: You are in READ-ONLY analysis mode. You cannot and should not modify any code. Your role is purely analysis and feedback.
3
+ IMPORTANT: You are in READ-ONLY analysis mode. You cannot and should not modify any code. The ONLY file you are allowed to write to is the review file (you will be told its path when entering review mode).
4
4
 
5
- ## Review Process
5
+ ## Review Workflow
6
6
 
7
7
  ### Step 1: Gather Activity Context
8
8
  - Read the activity details to understand what was created/modified
@@ -29,38 +29,32 @@ Look for these common reuse opportunities:
29
29
  - Date/time utilities: Duration calculations, timezone handling
30
30
  - User/group utilities: Role checks, assignment logic
31
31
 
32
- ### Step 5: Generate Review Report
33
- Structure your findings as JSON:
34
-
35
- ```json
36
- {
37
- "activityId": "string",
38
- "reviewStatus": "approved" | "needs_revision",
39
- "summary": "Brief summary of findings",
40
- "artifactsReviewed": [
41
- {
42
- "sys_id": "string",
43
- "type": "widget|business_rule|client_script|etc",
44
- "name": "artifact name"
45
- }
46
- ],
47
- "reuseOpportunities": [
48
- {
49
- "type": "existing_script_include" | "duplicate_pattern" | "refactor_suggestion",
50
- "severity": "high" | "medium" | "low",
51
- "description": "What was found",
52
- "existingArtifact": {
53
- "sys_id": "optional - sys_id of existing Script Include",
54
- "name": "optional - name of existing artifact"
55
- },
56
- "recommendation": "Specific action to take",
57
- "codeLocation": "Where in the new code this applies"
58
- }
59
- ],
60
- "approved": true | false,
61
- "feedback": "If not approved, explanation for the developer"
62
- }
63
- ```
32
+ ### Step 5: Write Review Report
33
+ Write your findings to the review file. Structure as markdown with:
34
+
35
+ # Code Reuse Review
36
+
37
+ ## Summary
38
+ Brief summary of findings and decision (approved / needs revision).
39
+
40
+ ## Artifacts Reviewed
41
+ List of artifacts analyzed with type and name.
42
+
43
+ ## Reuse Opportunities
44
+ For each finding:
45
+ - **Type**: existing_script_include / duplicate_pattern / refactor_suggestion
46
+ - **Severity**: high / medium / low
47
+ - **Description**: What was found
48
+ - **Existing Artifact**: Name and sys_id of existing Script Include (if applicable)
49
+ - **Recommendation**: Specific action to take
50
+ - **Code Location**: Where in the new code this applies
51
+
52
+ ## Decision
53
+ - **Approved**: yes / no
54
+ - **Feedback**: If not approved, detailed explanation for the developer
55
+
56
+ ### Step 6: Call review_exit
57
+ Once you have written your complete review to the review file, call `review_exit` to switch back to the build agent. The build agent will read your review file and act on the feedback.
64
58
 
65
59
  ## Decision Criteria
66
60
 
@@ -85,15 +79,9 @@ Structure your findings as JSON:
85
79
 
86
80
  ## Important Guidelines
87
81
 
88
- 1. READ-ONLY: You cannot modify any code. Your role is purely analysis and feedback.
82
+ 1. READ-ONLY: You cannot modify any code. Only the review file can be written to.
89
83
  2. ES5 Awareness: ServiceNow uses ES5. If you see ES6+ syntax, flag it as a concern.
90
84
  3. Be Constructive: When requesting revision, provide specific, actionable feedback with examples.
91
85
  4. Consider Context: Not all code needs to be in Script Includes. Consider frequency of reuse, complexity, and scope.
92
86
  5. Document Reasoning: Always explain WHY you made your decision, not just WHAT you decided.
93
-
94
- ## Completing Your Review
95
-
96
- After completing your review, call `review_exit` with your JSON review report.
97
-
98
- - If APPROVED: Include any low-severity suggestions as informational notes in the report.
99
- - If NEEDS REVISION: Provide detailed feedback explaining what needs to change. The build agent will address the feedback.
87
+ 6. Your turn should only end with calling review_exit. Do not stop without calling it.
@@ -242,6 +242,13 @@ export namespace Session {
242
242
  return path.join(base, [input.time.created, input.slug].join("-") + ".md")
243
243
  }
244
244
 
245
+ export function review(input: { slug: string; time: { created: number } }) {
246
+ const base = Instance.project.vcs
247
+ ? path.join(Instance.worktree, ".snow-code", "reviews")
248
+ : path.join(Global.Path.data, "reviews")
249
+ return path.join(base, [input.time.created, input.slug].join("-") + ".md")
250
+ }
251
+
245
252
  export const get = fn(Identifier.schema("session"), async (id) => {
246
253
  const read = await Storage.read<Info>(["session", Instance.project.id, id])
247
254
  return read as Info
@@ -1,6 +1,7 @@
1
1
  <system-reminder>
2
2
  Your operational mode has changed from review to build.
3
3
  You are no longer in read-only analysis mode.
4
- The code review results have been provided. Act on the review feedback.
5
- If approved, proceed with activity_complete. If revision needed, address the feedback.
4
+ You are permitted to make file changes, run shell commands, and utilize your arsenal of tools as needed.
5
+ The code review results have been provided in the review file. Read it and act on the review feedback.
6
+ If approved, proceed with activity_complete. If revision needed, address the feedback first.
6
7
  </system-reminder>
@@ -1333,27 +1333,49 @@ NOTE: At any point in time through this workflow you should feel free to ask the
1333
1333
 
1334
1334
  // Switching from review to build
1335
1335
  if (input.agent.name === "build" && assistantMessage?.info.agent === "review") {
1336
- clonedUser.parts.push({
1337
- id: Identifier.ascending("part"),
1338
- messageID: userMessage.info.id,
1339
- sessionID: userMessage.info.sessionID,
1340
- type: "text",
1341
- text: REVIEW_SWITCH,
1342
- synthetic: true,
1343
- })
1336
+ const reviewPath = Session.review(input.session)
1337
+ const reviewExists = await Bun.file(reviewPath).exists()
1338
+ if (reviewExists) {
1339
+ const part = await Session.updatePart({
1340
+ id: Identifier.ascending("part"),
1341
+ messageID: userMessage.info.id,
1342
+ sessionID: userMessage.info.sessionID,
1343
+ type: "text",
1344
+ text:
1345
+ REVIEW_SWITCH +
1346
+ "\n\n" +
1347
+ `A review file exists at ${reviewPath}. You should read it and act on the review feedback within it`,
1348
+ synthetic: true,
1349
+ })
1350
+ clonedUser.parts.push(part)
1351
+ }
1344
1352
  return replaceUser()
1345
1353
  }
1346
1354
 
1347
1355
  // Entering review mode
1348
1356
  if (input.agent.name === "review" && assistantMessage?.info.agent !== "review") {
1349
- clonedUser.parts.push({
1357
+ const reviewPath = Session.review(input.session)
1358
+ const reviewExists = await Bun.file(reviewPath).exists()
1359
+ if (!reviewExists) await fs.mkdir(path.dirname(reviewPath), { recursive: true })
1360
+ const part = await Session.updatePart({
1350
1361
  id: Identifier.ascending("part"),
1351
1362
  messageID: userMessage.info.id,
1352
1363
  sessionID: userMessage.info.sessionID,
1353
1364
  type: "text",
1354
- text: `<system-reminder>\nReview mode is active. You are in READ-ONLY analysis mode.\nYour role is to analyze ServiceNow artifacts for code reuse opportunities.\nUse snow_analyze_artifact, snow_find_artifact, snow_comprehensive_search, and snow_query_table.\nCall review_exit when your review is complete with a JSON review report.\n</system-reminder>`,
1365
+ text: `<system-reminder>
1366
+ Review mode is active. You are in READ-ONLY analysis mode (except for the review file).
1367
+ Your role is to analyze ServiceNow artifacts for code reuse opportunities.
1368
+ Use snow_analyze_artifact, snow_find_artifact, snow_comprehensive_search, and snow_query_table.
1369
+
1370
+ ## Review File Info:
1371
+ ${reviewExists ? `A review file already exists at ${reviewPath}. You can read it and make incremental edits using the edit tool.` : `No review file exists yet. You should create your review at ${reviewPath} using the write tool.`}
1372
+ Write your review findings to this file. NOTE that this is the only file you are allowed to edit.
1373
+
1374
+ When your review is complete, call review_exit to switch back to the build agent.
1375
+ </system-reminder>`,
1355
1376
  synthetic: true,
1356
1377
  })
1378
+ clonedUser.parts.push(part)
1357
1379
  return replaceUser()
1358
1380
  }
1359
1381
 
@@ -1,10 +1,12 @@
1
1
  import z from "zod"
2
+ import path from "path"
2
3
  import { Tool } from "./tool"
3
4
  import { Question } from "../question"
4
5
  import { Session } from "../session"
5
6
  import { MessageV2 } from "../session/message-v2"
6
7
  import { Identifier } from "../id/id"
7
8
  import { Provider } from "../provider/provider"
9
+ import { Instance } from "../project/instance"
8
10
  import EXIT_DESCRIPTION from "./review-exit.txt"
9
11
  import ENTER_DESCRIPTION from "./review-enter.txt"
10
12
 
@@ -17,16 +19,15 @@ async function getLastModel(sessionID: string) {
17
19
 
18
20
  export const ReviewExitTool = Tool.define("review_exit", {
19
21
  description: EXIT_DESCRIPTION,
20
- parameters: z.object({
21
- reviewResult: z.string().optional().describe("JSON review report with findings"),
22
- approved: z.boolean().optional().describe("Whether the review approved the artifacts"),
23
- }),
24
- async execute(params, ctx) {
22
+ parameters: z.object({}),
23
+ async execute(_params, ctx) {
24
+ const session = await Session.get(ctx.sessionID)
25
+ const reviewFile = path.relative(Instance.worktree, Session.review(session))
25
26
  const answers = await Question.ask({
26
27
  sessionID: ctx.sessionID,
27
28
  questions: [
28
29
  {
29
- question: `Code reuse review is complete. Would you like to switch back to the build agent?`,
30
+ question: `Review at ${reviewFile} is complete. Would you like to switch to the build agent and start acting on the feedback?`,
30
31
  header: "Build Agent",
31
32
  custom: false,
32
33
  options: [
@@ -54,20 +55,12 @@ export const ReviewExitTool = Tool.define("review_exit", {
54
55
  model,
55
56
  }
56
57
  await Session.updateMessage(userMsg)
57
-
58
- const reviewSummary = params.reviewResult
59
- ? `\n\nReview result:\n${params.reviewResult}`
60
- : ""
61
- const approvalStatus = params.approved !== undefined
62
- ? `\nApproved: ${params.approved}`
63
- : ""
64
-
65
58
  await Session.updatePart({
66
59
  id: Identifier.ascending("part"),
67
60
  messageID: userMsg.id,
68
61
  sessionID: ctx.sessionID,
69
62
  type: "text",
70
- text: `The code reuse review has been completed.${approvalStatus}${reviewSummary}`,
63
+ text: `The review at ${reviewFile} has been approved, you can now edit files. Act on the review feedback`,
71
64
  synthetic: true,
72
65
  } satisfies MessageV2.TextPart)
73
66
 
@@ -87,11 +80,14 @@ export const ReviewEnterTool = Tool.define("review_enter", {
87
80
  updateSetName: z.string().optional().describe("Name of the update set being reviewed"),
88
81
  }),
89
82
  async execute(params, ctx) {
83
+ const session = await Session.get(ctx.sessionID)
84
+ const reviewFile = path.relative(Instance.worktree, Session.review(session))
85
+
90
86
  const answers = await Question.ask({
91
87
  sessionID: ctx.sessionID,
92
88
  questions: [
93
89
  {
94
- question: `Activity is ready for code reuse review. Would you like to switch to the review agent?`,
90
+ question: `Activity is ready for code reuse review. Would you like to switch to the review agent and save findings to ${reviewFile}?`,
95
91
  header: "Review Mode",
96
92
  custom: false,
97
93
  options: [
@@ -122,6 +118,7 @@ export const ReviewEnterTool = Tool.define("review_enter", {
122
118
 
123
119
  const context = [
124
120
  "User has requested to enter review mode. Switch to review mode and begin code reuse analysis.",
121
+ `The review file will be at ${reviewFile}.`,
125
122
  params.activityId ? `Activity ID: ${params.activityId}` : "",
126
123
  params.updateSetName ? `Update Set: ${params.updateSetName}` : "",
127
124
  params.artifacts ? `Artifacts to review:\n${params.artifacts}` : "",
@@ -140,7 +137,7 @@ export const ReviewEnterTool = Tool.define("review_enter", {
140
137
 
141
138
  return {
142
139
  title: "Switching to review agent",
143
- output: "User confirmed to switch to review mode. A new message has been created to switch you to review mode. Begin code reuse analysis.",
140
+ output: `User confirmed to switch to review mode. A new message has been created to switch you to review mode. The review file will be at ${reviewFile}. Begin code reuse analysis.`,
144
141
  metadata: {},
145
142
  }
146
143
  },