@sweny-ai/core 0.1.177 → 0.1.178

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.
@@ -23,7 +23,7 @@ nodes:
23
23
  identifier wrapped in brackets — e.g. query
24
24
  `[OFF-1234] in:title type:pr state:open`. If the response contains
25
25
  one or more PRs whose title starts with `[<issueIdentifier>]`,
26
- STOP analysis. Output `existing_pr_url`
26
+ STOP analysis. Output `has_open_pr: true`, `existing_pr_url`
27
27
  (the URL of the open PR) and a short `issue_summary` noting the
28
28
  skip; leave `fix_plan` set to a one-line "Skip: open PR
29
29
  <url> already exists". The workflow will route to `notify` and
@@ -37,7 +37,12 @@ nodes:
37
37
  4. Identify the exact files and lines that need to change.
38
38
  5. Plan the fix approach.
39
39
 
40
- Output a clear analysis of what needs to change and why.
40
+ Output a clear analysis of what needs to change and why, plus three
41
+ routing fields: `has_open_pr` (true only when step 2 found an open PR),
42
+ `risk_level` (low, medium or high), and `plan_is_clear` (true only when
43
+ the plan names the exact files and changes). sweny implements the fix
44
+ only when there is no open PR, the risk is low or medium, and the plan
45
+ is clear; otherwise it skips.
41
46
  skills:
42
47
  - github
43
48
  - linear
@@ -68,9 +73,23 @@ nodes:
68
73
  and the analyze node is short-circuiting. Triggers the
69
74
  `analyze → notify` edge.
70
75
  pattern: "^https?://"
76
+ has_open_pr:
77
+ type: boolean
78
+ description: |
79
+ true when step 2 found an open PR for this issue (and
80
+ existing_pr_url is set), else false. Routes analyze to notify.
81
+ plan_is_clear:
82
+ type: boolean
83
+ description: |
84
+ true when fix_plan names the exact files and changes, so the fix
85
+ can be implemented without guessing; false when the fix is
86
+ unclear or needs a decision first.
71
87
  required:
72
88
  - issue_summary
73
89
  - fix_plan
90
+ - has_open_pr
91
+ - risk_level
92
+ - plan_is_clear
74
93
  implement:
75
94
  name: Implement Fix
76
95
  instruction: |-
@@ -182,15 +201,28 @@ nodes:
182
201
  max: 1
183
202
  number: { input: issueIdentifier }
184
203
  edges:
204
+ # Deterministic routing (#357), equivalent to the old natural-language
205
+ # conditions over declared fields: an open PR (has_open_pr, or
206
+ # existing_pr_url set, as the old condition read it) goes to notify;
207
+ # otherwise risk low or medium with a clear plan goes to implement;
208
+ # anything else (high risk or an unclear plan) takes the default edge to
209
+ # skip. The two expressions are exclusive (the implement one requires no
210
+ # open PR by either signal). A routing field still missing or invalid after
211
+ # sweny's repair request falls through to the agent, which reads the
212
+ # descriptions.
185
213
  - from: analyze
186
214
  to: notify
187
- when: analyze.existing_pr_url is set (an open PR for this issue already exists; skip the implement and create_pr nodes)
215
+ when:
216
+ expr: "analyze.has_open_pr == true || exists analyze.existing_pr_url"
217
+ description: an open PR for this issue already exists (analyze.existing_pr_url is set); skip the implement and create_pr nodes
188
218
  - from: analyze
189
219
  to: implement
190
- when: Fix risk level is low or medium and a clear plan exists
220
+ when:
221
+ expr: "analyze.has_open_pr == false && !(exists analyze.existing_pr_url) && analyze.risk_level in ['low', 'medium'] && analyze.plan_is_clear == true"
222
+ description: no open PR exists, the fix risk level is low or medium, and a clear plan exists
191
223
  - from: analyze
192
224
  to: skip
193
- when: Fix is too complex, risky, or unclear
225
+ description: the fix is too complex, risky, or unclear
194
226
  - from: implement
195
227
  to: create_pr
196
228
  - from: skip
@@ -109,6 +109,9 @@ nodes:
109
109
 
110
110
  - `novel_count`: how many findings are novel (not duplicates).
111
111
 
112
+ - `fixable_count`: how many NOVEL findings have `fix_complexity` simple or moderate AND a non-empty
113
+ `fix_approach`. 0 when none do. This decides whether sweny attempts a fix after filing the issue.
114
+
112
115
  - `highest_severity`: the highest severity across ALL findings.
113
116
 
114
117
  - `recommendation`: what should happen next.
@@ -190,6 +193,19 @@ nodes:
190
193
  novel_count:
191
194
  type: number
192
195
  description: Count of novel (non-duplicate) findings
196
+ fixable_count:
197
+ type: integer
198
+ minimum: 0
199
+ description: >-
200
+ Count of novel findings whose fix_complexity is simple or moderate AND
201
+ whose fix_approach is a non-empty plan. Routes create_issue to implement.
202
+ # sweny recounts this from `findings` and treats a disagreeing count as invalid (#357).
203
+ x-sweny-count-of:
204
+ array: findings
205
+ where:
206
+ is_duplicate: [false]
207
+ fix_complexity: [simple, moderate]
208
+ non_empty: [fix_approach]
193
209
  highest_severity:
194
210
  type: string
195
211
  enum:
@@ -202,6 +218,7 @@ nodes:
202
218
  required:
203
219
  - findings
204
220
  - novel_count
221
+ - fixable_count
205
222
  - highest_severity
206
223
  - recommendation
207
224
  create_issue:
@@ -796,33 +813,50 @@ edges:
796
813
  # Deterministic routing (#461): sweny evaluates these expressions over the
797
814
  # declared, required outputs of investigate, with no model call. The two
798
815
  # are complements over the declared enum, so exactly one is true.
816
+ #
817
+ # Every expression edge carries a `description`: the same condition in
818
+ # natural language. When a field an expression needs is still missing or
819
+ # invalid after sweny's one repair request, the route falls through to the
820
+ # agent, which decides on these descriptions (#357).
799
821
  - from: investigate
800
822
  to: create_issue
801
823
  when:
802
824
  expr: "investigate.novel_count > 0 && investigate.highest_severity in ['medium', 'high', 'critical']"
825
+ description: at least one novel finding, and the highest severity is medium or higher
803
826
  - from: investigate
804
827
  to: skip
805
828
  when:
806
829
  expr: "investigate.novel_count == 0 || investigate.highest_severity == 'low'"
830
+ description: no novel findings, or the highest severity is low
831
+ # Deterministic too (#357): fixable_count counts exactly the novel findings
832
+ # the old natural-language condition asked about (fix_complexity simple or
833
+ # moderate AND a fix_approach), so `> 0` is that condition and the default
834
+ # edge is its complement. sweny cross-checks the count against the
835
+ # findings (x-sweny-count-of): a count that disagrees with the findings is
836
+ # invalid, which reads as missing and falls through to the agent.
807
837
  - from: create_issue
808
838
  to: implement
809
- when: at least one novel finding has fix_complexity simple or moderate AND fix_approach is provided
839
+ when:
840
+ expr: "investigate.fixable_count > 0"
841
+ description: at least one novel finding has fix_complexity simple or moderate AND fix_approach is provided
810
842
  - from: create_issue
811
843
  to: notify
812
- when: all novel findings have fix_complexity complex, OR no clear fix_approach
844
+ description: all novel findings have fix_complexity complex, OR no clear fix_approach
813
845
  - from: skip
814
846
  to: notify
815
- # test_status is required and the node's eval only lets pass, no-framework
816
- # and skipped through (fail and not-run fail the node, which halts), so
817
- # exactly one of these is true. skipped: Step 0b found an open PR for the
818
- # issue, or Step 0 found a staged preview.
847
+ # The node's eval only lets test_status pass, no-framework and skipped
848
+ # through (fail and not-run fail the node, which halts), so exactly one of
849
+ # these is true. skipped: Step 0b found an open PR for the issue, or Step 0
850
+ # found a staged preview.
819
851
  - from: implement
820
852
  to: notify
821
853
  when:
822
854
  expr: "implement.test_status == 'skipped'"
855
+ description: the implement step was skipped (an open PR already exists, or a staged preview was found)
823
856
  - from: implement
824
857
  to: create_pr
825
858
  when:
826
859
  expr: "implement.test_status in ['pass', 'no-framework']"
860
+ description: the fix is committed and its tests passed (or the repo has no test framework)
827
861
  - from: create_pr
828
862
  to: notify
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sweny-ai/core",
3
- "version": "0.1.177",
3
+ "version": "0.1.178",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "sweny": "./dist/cli/main.js"