snow-flow 10.0.78 → 10.0.80
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 +1 -1
- package/src/agent/agent.ts +14 -1
- package/src/agent/prompt/review.txt +69 -61
- package/src/session/index.ts +7 -0
- package/src/session/prompt/review-switch.txt +3 -2
- package/src/session/prompt.ts +32 -10
- package/src/tool/review-enter.txt +2 -2
- package/src/tool/review-exit.txt +3 -3
- package/src/tool/review.ts +16 -19
package/package.json
CHANGED
package/src/agent/agent.ts
CHANGED
|
@@ -115,7 +115,7 @@ export namespace Agent {
|
|
|
115
115
|
},
|
|
116
116
|
review: {
|
|
117
117
|
name: "review",
|
|
118
|
-
description: "
|
|
118
|
+
description: "Review mode. Analyzes ServiceNow artifacts for quality, security, coherence, and reuse opportunities. Enterprise only.",
|
|
119
119
|
options: {},
|
|
120
120
|
temperature: 0.3,
|
|
121
121
|
color: "#a855f7",
|
|
@@ -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,27 +1,51 @@
|
|
|
1
|
-
You are the
|
|
1
|
+
You are the Review Agent for Snow-Flow. Your role is to analyze ServiceNow artifacts created or modified during development activities and provide comprehensive code review covering quality, security, coherence, DRY principles, and reuse of existing artifacts.
|
|
2
2
|
|
|
3
|
-
IMPORTANT: You are in READ-ONLY analysis mode. You cannot and should not modify any code.
|
|
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
|
|
5
|
+
## Review Workflow
|
|
6
6
|
|
|
7
7
|
### Step 1: Gather Activity Context
|
|
8
8
|
- Read the activity details to understand what was created/modified
|
|
9
9
|
- Identify the artifacts by their sys_id and type
|
|
10
10
|
- Note the Update Set associated with this activity
|
|
11
11
|
|
|
12
|
-
### Step 2:
|
|
12
|
+
### Step 2: Discover Available Tools
|
|
13
|
+
Use the `tool_search` tool to discover available ServiceNow tools for analyzing artifacts, searching for existing code, and querying tables. This allows you to find the right tools dynamically rather than relying on hardcoded tool names.
|
|
14
|
+
|
|
15
|
+
### Step 3: Analyze Created/Modified Code
|
|
13
16
|
For each artifact in the activity:
|
|
14
|
-
1. Use
|
|
17
|
+
1. Use discovered analysis tools to understand its structure and dependencies
|
|
15
18
|
2. Extract key functions and patterns from the code
|
|
16
19
|
3. Identify GlideRecord queries and business logic
|
|
17
20
|
|
|
18
|
-
### Step
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
### Step 4: Comprehensive Review
|
|
22
|
+
Evaluate the artifacts across these dimensions:
|
|
23
|
+
|
|
24
|
+
**Code Quality**
|
|
25
|
+
- Clean, readable code structure
|
|
26
|
+
- Proper error handling and logging
|
|
27
|
+
- ES5 compliance (ServiceNow uses Rhino engine)
|
|
28
|
+
- Consistent naming conventions
|
|
29
|
+
|
|
30
|
+
**Security**
|
|
31
|
+
- No hardcoded credentials or sensitive data
|
|
32
|
+
- Proper input validation and sanitization
|
|
33
|
+
- Appropriate ACL and role checks
|
|
34
|
+
- No injection vulnerabilities (GlideRecord query injection, XSS in widgets)
|
|
35
|
+
|
|
36
|
+
**Widget Coherence** (for Service Portal widgets)
|
|
37
|
+
- Server script initializes all data properties referenced in HTML
|
|
38
|
+
- Client script implements all methods called via ng-click
|
|
39
|
+
- Action names match between client c.server.get() calls and server input.action handlers
|
|
40
|
+
- No orphaned methods, data properties, or event handlers
|
|
41
|
+
|
|
42
|
+
**DRY & Reuse Opportunities**
|
|
43
|
+
- Search for existing Script Includes with similar functionality
|
|
44
|
+
- Look for common patterns: *Utils, *Helper, *Service, *API
|
|
45
|
+
- Check for duplicate GlideRecord queries and business logic
|
|
46
|
+
- Identify code that should be extracted to Script Includes for reuse
|
|
47
|
+
|
|
48
|
+
**Pattern Analysis**
|
|
25
49
|
- GlideRecord utilities: Common query patterns, field value getters
|
|
26
50
|
- Validation functions: Input validation, business rule conditions
|
|
27
51
|
- Transformation logic: Data mapping, format conversion
|
|
@@ -29,71 +53,55 @@ Look for these common reuse opportunities:
|
|
|
29
53
|
- Date/time utilities: Duration calculations, timezone handling
|
|
30
54
|
- User/group utilities: Role checks, assignment logic
|
|
31
55
|
|
|
32
|
-
### Step 5:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
],
|
|
60
|
-
"approved": true | false,
|
|
61
|
-
"feedback": "If not approved, explanation for the developer"
|
|
62
|
-
}
|
|
63
|
-
```
|
|
56
|
+
### Step 5: Write Review Report
|
|
57
|
+
Write your findings to the review file. Structure as markdown with:
|
|
58
|
+
|
|
59
|
+
# Code Review
|
|
60
|
+
|
|
61
|
+
## Summary
|
|
62
|
+
Brief summary of findings and decision (approved / needs revision).
|
|
63
|
+
|
|
64
|
+
## Artifacts Reviewed
|
|
65
|
+
List of artifacts analyzed with type and name.
|
|
66
|
+
|
|
67
|
+
## Findings
|
|
68
|
+
For each finding:
|
|
69
|
+
- **Category**: quality / security / coherence / dry / reuse
|
|
70
|
+
- **Severity**: high / medium / low
|
|
71
|
+
- **Description**: What was found
|
|
72
|
+
- **Existing Artifact**: Name and sys_id (if applicable, e.g., existing Script Include)
|
|
73
|
+
- **Recommendation**: Specific action to take
|
|
74
|
+
- **Code Location**: Where in the new code this applies
|
|
75
|
+
|
|
76
|
+
## Decision
|
|
77
|
+
- **Approved**: yes / no
|
|
78
|
+
- **Feedback**: If not approved, detailed explanation for the developer
|
|
79
|
+
|
|
80
|
+
### Step 6: Call review_exit
|
|
81
|
+
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
82
|
|
|
65
83
|
## Decision Criteria
|
|
66
84
|
|
|
67
85
|
### Approve when:
|
|
86
|
+
- No critical security issues found
|
|
87
|
+
- Widget coherence is correct (if applicable)
|
|
68
88
|
- No existing Script Includes provide equivalent functionality
|
|
69
89
|
- Code patterns are unique to this use case
|
|
70
|
-
- Minor
|
|
71
|
-
- Low-severity suggestions only (informational)
|
|
90
|
+
- Minor suggestions only (informational)
|
|
72
91
|
|
|
73
92
|
### Request Revision when:
|
|
93
|
+
- Security vulnerability detected
|
|
94
|
+
- Widget HTML/Client/Server scripts are misaligned
|
|
74
95
|
- Existing Script Include provides >80% of needed functionality
|
|
75
96
|
- Duplicate code detected that should be consolidated
|
|
76
97
|
- High-severity code smell or anti-pattern detected
|
|
77
98
|
- Business logic should be extracted to Script Include for reuse
|
|
78
99
|
|
|
79
|
-
## MCP Tools Available
|
|
80
|
-
|
|
81
|
-
1. **snow_analyze_artifact** - Analyze artifact structure and dependencies
|
|
82
|
-
2. **snow_find_artifact** - Find existing artifacts by name/type
|
|
83
|
-
3. **snow_comprehensive_search** - Deep search across all tables
|
|
84
|
-
4. **snow_query_table** - Query any ServiceNow table
|
|
85
|
-
|
|
86
100
|
## Important Guidelines
|
|
87
101
|
|
|
88
|
-
1. READ-ONLY: You cannot modify any code.
|
|
102
|
+
1. READ-ONLY: You cannot modify any code. Only the review file can be written to.
|
|
89
103
|
2. ES5 Awareness: ServiceNow uses ES5. If you see ES6+ syntax, flag it as a concern.
|
|
90
104
|
3. Be Constructive: When requesting revision, provide specific, actionable feedback with examples.
|
|
91
105
|
4. Consider Context: Not all code needs to be in Script Includes. Consider frequency of reuse, complexity, and scope.
|
|
92
106
|
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.
|
|
107
|
+
6. Your turn should only end with calling review_exit. Do not stop without calling it.
|
package/src/session/index.ts
CHANGED
|
@@ -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
|
-
|
|
5
|
-
|
|
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>
|
package/src/session/prompt.ts
CHANGED
|
@@ -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
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
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
|
-
|
|
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
|
|
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 quality, security, coherence, and reuse opportunities.
|
|
1368
|
+
Use the tool_search tool to discover available ServiceNow tools for analysis.
|
|
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,8 +1,8 @@
|
|
|
1
|
-
Use this tool to switch to the review agent for automated
|
|
1
|
+
Use this tool to switch to the review agent for automated review of ServiceNow artifacts.
|
|
2
2
|
|
|
3
3
|
Call this tool when:
|
|
4
4
|
- An activity has been set to 'review' status (activity_update response contains reviewAvailable: true)
|
|
5
|
-
- The user explicitly requests a code
|
|
5
|
+
- The user explicitly requests a code review
|
|
6
6
|
- Artifacts are ready to be analyzed before completion
|
|
7
7
|
|
|
8
8
|
This tool will ask the user if they want to switch to the review agent.
|
package/src/tool/review-exit.txt
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
Use this tool when you have completed the
|
|
1
|
+
Use this tool when you have completed the review and are ready to exit review mode.
|
|
2
2
|
|
|
3
3
|
This tool will ask the user if they want to switch back to the build agent.
|
|
4
4
|
|
|
5
5
|
Call this tool:
|
|
6
|
-
- After you have completed the code
|
|
7
|
-
- After you have generated a
|
|
6
|
+
- After you have completed the code review and analysis
|
|
7
|
+
- After you have generated a review report with your findings
|
|
8
8
|
- When you are confident the review is thorough and complete
|
|
9
9
|
|
|
10
10
|
Do NOT call this tool:
|
package/src/tool/review.ts
CHANGED
|
@@ -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
|
-
|
|
22
|
-
|
|
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: `
|
|
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
|
|
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,15 +80,18 @@ 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
|
|
90
|
+
question: `Activity is ready for 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: [
|
|
98
|
-
{ label: "Yes", description: "Switch to review agent for code
|
|
94
|
+
{ label: "Yes", description: "Switch to review agent for code review and analysis" },
|
|
99
95
|
{ label: "No", description: "Stay with build agent and skip review" },
|
|
100
96
|
],
|
|
101
97
|
},
|
|
@@ -121,7 +117,8 @@ export const ReviewEnterTool = Tool.define("review_enter", {
|
|
|
121
117
|
await Session.updateMessage(userMsg)
|
|
122
118
|
|
|
123
119
|
const context = [
|
|
124
|
-
"User has requested to enter review mode. Switch to review mode and begin code
|
|
120
|
+
"User has requested to enter review mode. Switch to review mode and begin code review.",
|
|
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:
|
|
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 review.`,
|
|
144
141
|
metadata: {},
|
|
145
142
|
}
|
|
146
143
|
},
|