prizmkit 1.1.1 → 1.1.4

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.
Files changed (119) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/adapters/claude/agent-adapter.js +18 -0
  3. package/bundled/adapters/claude/command-adapter.js +1 -27
  4. package/bundled/agents/prizm-dev-team-critic.md +2 -0
  5. package/bundled/agents/prizm-dev-team-dev.md +2 -0
  6. package/bundled/agents/prizm-dev-team-reviewer.md +2 -0
  7. package/bundled/dev-pipeline/README.md +63 -63
  8. package/bundled/dev-pipeline/assets/feature-list-example.json +1 -1
  9. package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +1 -1
  10. package/bundled/dev-pipeline/{launch-daemon.sh → launch-feature-daemon.sh} +33 -33
  11. package/bundled/dev-pipeline/launch-refactor-daemon.sh +454 -0
  12. package/bundled/dev-pipeline/lib/branch.sh +1 -1
  13. package/bundled/dev-pipeline/reset-feature.sh +3 -3
  14. package/bundled/dev-pipeline/reset-refactor.sh +312 -0
  15. package/bundled/dev-pipeline/{retry-bug.sh → retry-bugfix.sh} +47 -59
  16. package/bundled/dev-pipeline/retry-feature.sh +41 -54
  17. package/bundled/dev-pipeline/retry-refactor.sh +358 -0
  18. package/bundled/dev-pipeline/run-bugfix.sh +41 -0
  19. package/bundled/dev-pipeline/{run.sh → run-feature.sh} +64 -31
  20. package/bundled/dev-pipeline/run-refactor.sh +787 -0
  21. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +398 -10
  22. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +124 -0
  23. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +419 -0
  24. package/bundled/dev-pipeline/scripts/init-refactor-pipeline.py +393 -0
  25. package/bundled/dev-pipeline/scripts/update-refactor-status.py +726 -0
  26. package/bundled/dev-pipeline/templates/agent-prompts/critic-code-challenge.md +13 -0
  27. package/bundled/dev-pipeline/templates/agent-prompts/critic-plan-challenge.md +7 -0
  28. package/bundled/dev-pipeline/templates/agent-prompts/dev-fix.md +7 -0
  29. package/bundled/dev-pipeline/templates/agent-prompts/dev-implement.md +27 -0
  30. package/bundled/dev-pipeline/templates/agent-prompts/dev-resume.md +5 -0
  31. package/bundled/dev-pipeline/templates/agent-prompts/reviewer-analyze.md +5 -0
  32. package/bundled/dev-pipeline/templates/agent-prompts/reviewer-review.md +12 -0
  33. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +33 -2
  34. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +13 -9
  35. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +16 -12
  36. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +22 -4
  37. package/bundled/dev-pipeline/templates/feature-list-schema.json +1 -1
  38. package/bundled/dev-pipeline/templates/refactor-list-schema.json +159 -0
  39. package/bundled/dev-pipeline/templates/sections/ac-verification-checklist.md +13 -0
  40. package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +36 -0
  41. package/bundled/dev-pipeline/templates/sections/failure-log-check.md +2 -1
  42. package/bundled/dev-pipeline/templates/sections/feature-context.md +1 -1
  43. package/bundled/dev-pipeline/templates/sections/phase-analyze-agent.md +11 -7
  44. package/bundled/dev-pipeline/templates/sections/phase-analyze-full.md +11 -7
  45. package/bundled/dev-pipeline/templates/sections/phase-browser-verification.md +5 -1
  46. package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +3 -0
  47. package/bundled/dev-pipeline/templates/sections/phase-commit.md +3 -0
  48. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +3 -0
  49. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-lite-suffix.md +3 -0
  50. package/bundled/dev-pipeline/templates/sections/phase-critic-code.md +11 -10
  51. package/bundled/dev-pipeline/templates/sections/phase-critic-plan-full.md +12 -10
  52. package/bundled/dev-pipeline/templates/sections/phase-critic-plan.md +11 -9
  53. package/bundled/dev-pipeline/templates/sections/phase-deploy-verification.md +3 -0
  54. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +10 -10
  55. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +12 -16
  56. package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +3 -0
  57. package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +3 -0
  58. package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +3 -0
  59. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +11 -13
  60. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +12 -20
  61. package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +3 -0
  62. package/bundled/dev-pipeline/templates/sections/phase0-init.md +3 -0
  63. package/bundled/dev-pipeline/templates/sections/phase0-test-baseline.md +3 -0
  64. package/bundled/dev-pipeline/templates/sections/resume-header.md +4 -1
  65. package/bundled/dev-pipeline/templates/sections/test-failure-recovery.md +75 -0
  66. package/bundled/rules/prizm/prizm-commit-workflow.md +1 -0
  67. package/bundled/rules/prizm/prizm-documentation.md +15 -15
  68. package/bundled/rules/prizm/prizm-progressive-loading.md +2 -1
  69. package/bundled/skills/_metadata.json +33 -6
  70. package/bundled/skills/app-planner/SKILL.md +105 -320
  71. package/bundled/skills/app-planner/assets/app-design-guide.md +101 -0
  72. package/bundled/skills/app-planner/references/frontend-design-guide.md +1 -1
  73. package/bundled/skills/app-planner/references/project-brief-guide.md +49 -80
  74. package/bundled/skills/bug-fix-workflow/SKILL.md +2 -2
  75. package/bundled/skills/bug-planner/SKILL.md +68 -5
  76. package/bundled/skills/bug-planner/scripts/validate-bug-list.py +3 -2
  77. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +19 -5
  78. package/bundled/skills/{dev-pipeline-launcher → feature-pipeline-launcher}/SKILL.md +32 -32
  79. package/bundled/skills/feature-planner/SKILL.md +337 -0
  80. package/bundled/skills/{app-planner → feature-planner}/assets/evaluation-guide.md +4 -4
  81. package/bundled/skills/{app-planner → feature-planner}/assets/planning-guide.md +3 -171
  82. package/bundled/skills/{app-planner → feature-planner}/references/browser-interaction.md +6 -5
  83. package/bundled/skills/feature-planner/references/decomposition-patterns.md +75 -0
  84. package/bundled/skills/{app-planner → feature-planner}/references/error-recovery.md +8 -8
  85. package/bundled/skills/{app-planner → feature-planner}/references/incremental-feature-planning.md +1 -1
  86. package/bundled/skills/{app-planner/references/new-app-planning.md → feature-planner/references/new-project-planning.md} +1 -1
  87. package/bundled/skills/{app-planner → feature-planner}/scripts/validate-and-generate.py +4 -4
  88. package/bundled/skills/feature-workflow/SKILL.md +23 -23
  89. package/bundled/skills/prizm-kit/SKILL.md +1 -3
  90. package/bundled/skills/prizm-kit/assets/project-memory-template.md +4 -2
  91. package/bundled/skills/prizmkit-analyze/SKILL.md +2 -5
  92. package/bundled/skills/prizmkit-code-review/SKILL.md +2 -2
  93. package/bundled/skills/prizmkit-committer/SKILL.md +32 -8
  94. package/bundled/skills/prizmkit-deploy/SKILL.md +1 -5
  95. package/bundled/skills/prizmkit-implement/SKILL.md +5 -51
  96. package/bundled/skills/prizmkit-init/SKILL.md +7 -78
  97. package/bundled/skills/prizmkit-plan/SKILL.md +1 -12
  98. package/bundled/skills/prizmkit-prizm-docs/SKILL.md +13 -28
  99. package/bundled/skills/prizmkit-prizm-docs/assets/PRIZM-SPEC.md +52 -1
  100. package/bundled/skills/prizmkit-retrospective/SKILL.md +12 -117
  101. package/bundled/skills/recovery-workflow/SKILL.md +168 -316
  102. package/bundled/skills/recovery-workflow/evals/evals.json +29 -13
  103. package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +232 -274
  104. package/bundled/skills/refactor-pipeline-launcher/SKILL.md +352 -0
  105. package/bundled/skills/refactor-planner/SKILL.md +436 -0
  106. package/bundled/skills/refactor-planner/assets/planning-guide.md +292 -0
  107. package/bundled/skills/refactor-planner/references/behavior-preservation.md +301 -0
  108. package/bundled/skills/refactor-planner/references/refactor-scoping-guide.md +221 -0
  109. package/bundled/skills/refactor-planner/scripts/validate-and-generate-refactor.py +786 -0
  110. package/bundled/skills/refactor-workflow/SKILL.md +299 -319
  111. package/bundled/team/prizm-dev-team.json +1 -1
  112. package/package.json +1 -1
  113. package/src/clean.js +3 -3
  114. package/src/scaffold.js +6 -6
  115. package/bundled/skills/prizmkit-plan/assets/spec-template.md +0 -56
  116. package/bundled/skills/prizmkit-plan/references/clarify-guide.md +0 -67
  117. package/src/config.js +0 -504
  118. package/src/prompts.js +0 -210
  119. /package/bundled/skills/{dev-pipeline-launcher → feature-pipeline-launcher}/scripts/preflight-check.py +0 -0
@@ -0,0 +1,393 @@
1
+ #!/usr/bin/env python3
2
+ """Initialize the refactor pipeline state directory from a refactor-list.json file.
3
+
4
+ Validates the refactor list schema, sorts by priority/complexity, checks for
5
+ circular dependencies, and creates the state directory structure with pipeline
6
+ and per-refactor status files.
7
+
8
+ Usage:
9
+ python3 init-refactor-pipeline.py --refactor-list <path> --state-dir <path>
10
+ """
11
+
12
+ import argparse
13
+ import json
14
+ import os
15
+ import re
16
+ import sys
17
+ from datetime import datetime, timezone
18
+
19
+ from utils import load_json_file
20
+
21
+
22
+ EXPECTED_SCHEMA = "dev-pipeline-refactor-list-v1"
23
+ REFACTOR_ID_PATTERN = re.compile(r"^R-\d{3}$")
24
+
25
+ REQUIRED_REFACTOR_FIELDS = [
26
+ "id",
27
+ "title",
28
+ "description",
29
+ "scope",
30
+ "type",
31
+ "priority",
32
+ "complexity",
33
+ "behavior_preservation",
34
+ "acceptance_criteria",
35
+ "dependencies",
36
+ "status",
37
+ ]
38
+
39
+ VALID_TYPES = ["extract", "rename", "restructure", "simplify", "decouple", "migrate"]
40
+ VALID_PRIORITIES = ["critical", "high", "medium", "low"]
41
+ VALID_COMPLEXITIES = ["low", "medium", "high"]
42
+ VALID_STATUSES = [
43
+ "pending", "in_progress", "completed", "failed", "skipped",
44
+ ]
45
+ VALID_BEHAVIOR_STRATEGIES = ["test-gate", "snapshot", "manual"]
46
+
47
+
48
+ def parse_args():
49
+ parser = argparse.ArgumentParser(
50
+ description="Initialize refactor pipeline state from a refactor-list.json file."
51
+ )
52
+ parser.add_argument(
53
+ "--refactor-list",
54
+ required=True,
55
+ help="Path to the refactor-list.json file",
56
+ )
57
+ parser.add_argument(
58
+ "--state-dir",
59
+ required=True,
60
+ help="Path to the state directory to create/initialize",
61
+ )
62
+ return parser.parse_args()
63
+
64
+
65
+ def load_refactor_list(path):
66
+ """Load and return the parsed JSON from the refactor list file."""
67
+ data, err = load_json_file(path)
68
+ if err:
69
+ return None, [err]
70
+ return data, []
71
+
72
+
73
+ def validate_schema(data):
74
+ """Validate the top-level schema and structure of the refactor list."""
75
+ errors = []
76
+
77
+ # Check $schema
78
+ schema = data.get("$schema")
79
+ if schema != EXPECTED_SCHEMA:
80
+ errors.append(
81
+ "Invalid $schema: expected '{}', got '{}'".format(EXPECTED_SCHEMA, schema)
82
+ )
83
+
84
+ # Check project_name
85
+ if "project_name" not in data:
86
+ errors.append("Missing required field: project_name")
87
+ elif not isinstance(data["project_name"], str) or not data["project_name"].strip():
88
+ errors.append("project_name must be a non-empty string")
89
+
90
+ # Check refactors array
91
+ if "refactors" not in data:
92
+ errors.append("Missing required field: refactors")
93
+ elif not isinstance(data["refactors"], list):
94
+ errors.append("refactors must be an array")
95
+ elif len(data["refactors"]) == 0:
96
+ errors.append("refactors array must contain at least one refactor")
97
+
98
+ return errors
99
+
100
+
101
+ def validate_refactors(refactors):
102
+ """Validate each refactor object in the list."""
103
+ errors = []
104
+ seen_ids = set()
105
+
106
+ for i, refactor in enumerate(refactors):
107
+ if not isinstance(refactor, dict):
108
+ errors.append("Refactor at index {} is not an object".format(i))
109
+ continue
110
+
111
+ # Check required fields
112
+ for field in REQUIRED_REFACTOR_FIELDS:
113
+ if field not in refactor:
114
+ errors.append(
115
+ "Refactor at index {} missing required field: {}".format(i, field)
116
+ )
117
+
118
+ # Validate refactor ID format
119
+ rid = refactor.get("id")
120
+ if rid is not None:
121
+ if not isinstance(rid, str) or not REFACTOR_ID_PATTERN.match(rid):
122
+ errors.append(
123
+ "Refactor at index {} has invalid id '{}' "
124
+ "(must match R-NNN pattern)".format(i, rid)
125
+ )
126
+ elif rid in seen_ids:
127
+ errors.append("Duplicate refactor id: {}".format(rid))
128
+ else:
129
+ seen_ids.add(rid)
130
+
131
+ # Validate type
132
+ rtype = refactor.get("type")
133
+ if rtype is not None and rtype not in VALID_TYPES:
134
+ errors.append(
135
+ "Refactor '{}' has invalid type '{}' "
136
+ "(must be one of {})".format(
137
+ rid or "index {}".format(i), rtype, VALID_TYPES
138
+ )
139
+ )
140
+
141
+ # Validate priority
142
+ priority = refactor.get("priority")
143
+ if priority is not None and priority not in VALID_PRIORITIES:
144
+ errors.append(
145
+ "Refactor '{}' has invalid priority '{}' "
146
+ "(must be one of {})".format(
147
+ rid or "index {}".format(i), priority, VALID_PRIORITIES
148
+ )
149
+ )
150
+
151
+ # Validate complexity
152
+ complexity = refactor.get("complexity")
153
+ if complexity is not None and complexity not in VALID_COMPLEXITIES:
154
+ errors.append(
155
+ "Refactor '{}' has invalid complexity '{}' "
156
+ "(must be one of {})".format(
157
+ rid or "index {}".format(i), complexity, VALID_COMPLEXITIES
158
+ )
159
+ )
160
+
161
+ # Validate status
162
+ status = refactor.get("status")
163
+ if status is not None and status not in VALID_STATUSES:
164
+ errors.append(
165
+ "Refactor '{}' has invalid status '{}' "
166
+ "(must be one of {})".format(
167
+ rid or "index {}".format(i), status, VALID_STATUSES
168
+ )
169
+ )
170
+
171
+ # Validate scope is an object
172
+ scope = refactor.get("scope")
173
+ if scope is not None:
174
+ if not isinstance(scope, dict):
175
+ errors.append(
176
+ "Refactor '{}' scope must be an object".format(
177
+ rid or "index {}".format(i)
178
+ )
179
+ )
180
+
181
+ # Validate behavior_preservation
182
+ bp = refactor.get("behavior_preservation")
183
+ if bp is not None:
184
+ if not isinstance(bp, dict):
185
+ errors.append(
186
+ "Refactor '{}' behavior_preservation must be an object".format(
187
+ rid or "index {}".format(i)
188
+ )
189
+ )
190
+ else:
191
+ strategy = bp.get("strategy")
192
+ if strategy is not None and strategy not in VALID_BEHAVIOR_STRATEGIES:
193
+ errors.append(
194
+ "Refactor '{}' behavior_preservation.strategy '{}' "
195
+ "must be one of {}".format(
196
+ rid or "index {}".format(i), strategy, VALID_BEHAVIOR_STRATEGIES
197
+ )
198
+ )
199
+
200
+ # Validate acceptance_criteria is a list
201
+ ac = refactor.get("acceptance_criteria")
202
+ if ac is not None and not isinstance(ac, list):
203
+ errors.append(
204
+ "Refactor '{}' acceptance_criteria must be an array".format(
205
+ rid or "index {}".format(i)
206
+ )
207
+ )
208
+
209
+ # Validate dependencies is a list
210
+ deps = refactor.get("dependencies")
211
+ if deps is not None and not isinstance(deps, list):
212
+ errors.append(
213
+ "Refactor '{}' dependencies must be an array".format(
214
+ rid or "index {}".format(i)
215
+ )
216
+ )
217
+
218
+ return errors, seen_ids
219
+
220
+
221
+ def check_circular_dependencies(refactors):
222
+ """Check for circular dependencies among refactors. Returns list of error strings."""
223
+ errors = []
224
+
225
+ # Build adjacency map: id -> list of dependency ids
226
+ dep_map = {}
227
+ valid_ids = set()
228
+ for refactor in refactors:
229
+ if not isinstance(refactor, dict):
230
+ continue
231
+ rid = refactor.get("id")
232
+ if not rid:
233
+ continue
234
+ valid_ids.add(rid)
235
+ deps = refactor.get("dependencies", [])
236
+ if isinstance(deps, list):
237
+ dep_map[rid] = [d for d in deps if isinstance(d, str)]
238
+ else:
239
+ dep_map[rid] = []
240
+
241
+ # Check that all dependency references point to valid IDs
242
+ for rid, deps in dep_map.items():
243
+ for dep_id in deps:
244
+ if dep_id not in valid_ids:
245
+ errors.append(
246
+ "Refactor '{}' depends on '{}' which does not exist".format(rid, dep_id)
247
+ )
248
+
249
+ # DFS cycle detection
250
+ WHITE, GRAY, BLACK = 0, 1, 2
251
+ color = {rid: WHITE for rid in valid_ids}
252
+
253
+ def dfs(node, path):
254
+ color[node] = GRAY
255
+ path.append(node)
256
+ for neighbor in dep_map.get(node, []):
257
+ if neighbor not in color:
258
+ continue
259
+ if color[neighbor] == GRAY:
260
+ # Found a cycle
261
+ cycle_start = path.index(neighbor)
262
+ cycle = path[cycle_start:] + [neighbor]
263
+ errors.append(
264
+ "Circular dependency detected: {}".format(" -> ".join(cycle))
265
+ )
266
+ return
267
+ if color[neighbor] == WHITE:
268
+ dfs(neighbor, path)
269
+ path.pop()
270
+ color[node] = BLACK
271
+
272
+ for rid in valid_ids:
273
+ if color[rid] == WHITE:
274
+ dfs(rid, [])
275
+
276
+ return errors
277
+
278
+
279
+ def create_state_directory(state_dir, refactor_list_path, refactors):
280
+ """Create the state directory structure with pipeline.json and per-refactor status files."""
281
+ abs_state_dir = os.path.abspath(state_dir)
282
+ abs_refactor_list_path = os.path.abspath(refactor_list_path)
283
+ # Store as relative path from state_dir so pipeline.json is portable across machines
284
+ rel_refactor_list_path = os.path.relpath(abs_refactor_list_path, abs_state_dir)
285
+ refactors_dir = os.path.join(abs_state_dir, "refactors")
286
+
287
+ now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
288
+ run_id = "refactor-run-" + datetime.now(timezone.utc).strftime("%Y%m%d%H%M")
289
+
290
+ # Create top-level state directory
291
+ os.makedirs(abs_state_dir, exist_ok=True)
292
+ os.makedirs(refactors_dir, exist_ok=True)
293
+
294
+ # Write pipeline.json
295
+ pipeline_state = {
296
+ "run_id": run_id,
297
+ "pipeline_type": "refactor",
298
+ "status": "initialized",
299
+ "refactor_list_path": rel_refactor_list_path,
300
+ "created_at": now,
301
+ "total_refactors": len(refactors),
302
+ "completed_refactors": 0,
303
+ }
304
+ pipeline_path = os.path.join(abs_state_dir, "pipeline.json")
305
+ with open(pipeline_path, "w", encoding="utf-8") as f:
306
+ json.dump(pipeline_state, f, indent=2, ensure_ascii=False)
307
+ f.write("\n")
308
+
309
+ # Write per-refactor status.json and create sessions directory
310
+ for refactor in refactors:
311
+ if not isinstance(refactor, dict):
312
+ continue
313
+ rid = refactor.get("id")
314
+ if rid is None:
315
+ continue
316
+
317
+ refactor_dir = os.path.join(refactors_dir, rid)
318
+ sessions_dir = os.path.join(refactor_dir, "sessions")
319
+ os.makedirs(sessions_dir, exist_ok=True)
320
+
321
+ refactor_status = {
322
+ "refactor_id": rid,
323
+ "status": "pending",
324
+ "retry_count": 0,
325
+ "max_retries": 3,
326
+ "sessions": [],
327
+ "last_session_id": None,
328
+ "resume_from_phase": None,
329
+ "created_at": now,
330
+ "updated_at": now,
331
+ }
332
+ status_path = os.path.join(refactor_dir, "status.json")
333
+ with open(status_path, "w", encoding="utf-8") as f:
334
+ json.dump(refactor_status, f, indent=2, ensure_ascii=False)
335
+ f.write("\n")
336
+
337
+ return abs_state_dir
338
+
339
+
340
+ def main():
341
+ args = parse_args()
342
+
343
+ # Load refactor list
344
+ data, load_errors = load_refactor_list(args.refactor_list)
345
+ if load_errors:
346
+ output = {"valid": False, "errors": load_errors}
347
+ print(json.dumps(output, indent=2, ensure_ascii=False))
348
+ sys.exit(1)
349
+
350
+ # Validate schema
351
+ schema_errors = validate_schema(data)
352
+ if schema_errors:
353
+ output = {"valid": False, "errors": schema_errors}
354
+ print(json.dumps(output, indent=2, ensure_ascii=False))
355
+ sys.exit(1)
356
+
357
+ # Validate refactors
358
+ refactors = data["refactors"]
359
+ refactor_errors, refactor_ids = validate_refactors(refactors)
360
+ if refactor_errors:
361
+ output = {"valid": False, "errors": refactor_errors}
362
+ print(json.dumps(output, indent=2, ensure_ascii=False))
363
+ sys.exit(1)
364
+
365
+ # Check for circular dependencies
366
+ dep_errors = check_circular_dependencies(refactors)
367
+ if dep_errors:
368
+ output = {"valid": False, "errors": dep_errors}
369
+ print(json.dumps(output, indent=2, ensure_ascii=False))
370
+ sys.exit(1)
371
+
372
+ # Create state directory
373
+ try:
374
+ abs_state_dir = create_state_directory(
375
+ args.state_dir, args.refactor_list, refactors
376
+ )
377
+ except (IOError, OSError) as e:
378
+ output = {"valid": False, "errors": ["Failed to create state directory: {}".format(str(e))]}
379
+ print(json.dumps(output, indent=2, ensure_ascii=False))
380
+ sys.exit(1)
381
+
382
+ # Success output
383
+ output = {
384
+ "valid": True,
385
+ "refactors_count": len(refactors),
386
+ "state_dir": abs_state_dir,
387
+ }
388
+ print(json.dumps(output, indent=2, ensure_ascii=False))
389
+ sys.exit(0)
390
+
391
+
392
+ if __name__ == "__main__":
393
+ main()