prizmkit 1.1.148 → 1.1.150
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/bundled/VERSION.json +3 -3
- package/bundled/dev-pipeline/README.md +20 -17
- package/bundled/dev-pipeline/prizmkit_runtime/checkpoint_state.py +77 -0
- package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +234 -39
- package/bundled/dev-pipeline/prizmkit_runtime/reset.py +57 -30
- package/bundled/dev-pipeline/prizmkit_runtime/reset_preserve.py +822 -0
- package/bundled/dev-pipeline/prizmkit_runtime/runner_bookkeeping.py +28 -11
- package/bundled/dev-pipeline/prizmkit_runtime/runners.py +71 -28
- package/bundled/dev-pipeline/prizmkit_runtime/task_checkout.py +18 -0
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +67 -13
- package/bundled/dev-pipeline/tests/test_reset_preserve.py +959 -0
- package/bundled/dev-pipeline/tests/test_unified_cli.py +325 -5
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/app-planner/SKILL.md +27 -27
- package/bundled/skills/app-planner/references/architecture-decisions.md +5 -11
- package/bundled/skills/app-planner/references/frontend-design-guide.md +1 -1
- package/bundled/skills/app-planner/references/generated-plan-review.md +2 -2
- package/bundled/skills/app-planner/references/infrastructure-convention-discovery.md +2 -2
- package/bundled/skills/app-planner/references/project-conventions-discovery.md +1 -1
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +21 -9
- package/bundled/skills/feature-pipeline-launcher/SKILL.md +21 -9
- package/bundled/skills/refactor-pipeline-launcher/SKILL.md +21 -9
- package/bundled/templates/project-memory-template.md +38 -0
- package/package.json +1 -1
|
@@ -39,7 +39,7 @@ class ResetOptions:
|
|
|
39
39
|
item_range: tuple[str, str] | None = None
|
|
40
40
|
filter_mode: str = ""
|
|
41
41
|
clean: bool = False
|
|
42
|
-
|
|
42
|
+
preserve_runtime: bool = False
|
|
43
43
|
help_requested: bool = False
|
|
44
44
|
unknown_args: tuple[str, ...] = ()
|
|
45
45
|
|
|
@@ -99,14 +99,20 @@ STALLED_FILTER_STATUSES = {
|
|
|
99
99
|
def run_reset_command(kind: str, legacy_args: tuple[str, ...], paths) -> CommandResult:
|
|
100
100
|
"""Run a manual reset command for feature, bugfix, or refactor."""
|
|
101
101
|
family = family_for(kind, paths)
|
|
102
|
-
|
|
102
|
+
try:
|
|
103
|
+
options = _parse_reset_args(family, legacy_args)
|
|
104
|
+
except ValueError as exc:
|
|
105
|
+
return CommandResult(2, f"Python {kind} reset", str(exc))
|
|
103
106
|
if options.help_requested:
|
|
104
107
|
return CommandResult(0, f"Python {kind} reset", _help_text(family), stdout=_help_text(family))
|
|
108
|
+
option_error = _reset_option_error(family, options)
|
|
109
|
+
if option_error:
|
|
110
|
+
return CommandResult(2, f"Python {kind} reset", option_error)
|
|
105
111
|
|
|
106
112
|
list_path = _resolve_list_path(options.list_path, paths.project_root)
|
|
107
113
|
if not list_path.is_file():
|
|
108
114
|
return CommandResult(1, f"Python {kind} reset", f"{kind} list not found: {list_path}")
|
|
109
|
-
if not (family.state_dir / "pipeline.json").is_file():
|
|
115
|
+
if not options.preserve_runtime and not (family.state_dir / "pipeline.json").is_file():
|
|
110
116
|
return CommandResult(1, f"Python {kind} reset", f"No pipeline state found. Run the {kind} pipeline first to initialize.")
|
|
111
117
|
|
|
112
118
|
options = ResetOptions(
|
|
@@ -115,10 +121,26 @@ def run_reset_command(kind: str, legacy_args: tuple[str, ...], paths) -> Command
|
|
|
115
121
|
item_range=options.item_range,
|
|
116
122
|
filter_mode=options.filter_mode,
|
|
117
123
|
clean=options.clean,
|
|
118
|
-
|
|
124
|
+
preserve_runtime=options.preserve_runtime,
|
|
119
125
|
help_requested=options.help_requested,
|
|
120
126
|
unknown_args=options.unknown_args,
|
|
121
127
|
)
|
|
128
|
+
if options.preserve_runtime:
|
|
129
|
+
from .reset_preserve import run_preserve_runtime_reset
|
|
130
|
+
|
|
131
|
+
preserve_result = run_preserve_runtime_reset(
|
|
132
|
+
family,
|
|
133
|
+
options.list_path,
|
|
134
|
+
paths.project_root,
|
|
135
|
+
)
|
|
136
|
+
text = "\n".join(preserve_result.lines(family, options.list_path))
|
|
137
|
+
return CommandResult(
|
|
138
|
+
0 if preserve_result.ok else 1,
|
|
139
|
+
f"Python {kind} reset",
|
|
140
|
+
text,
|
|
141
|
+
stdout=text,
|
|
142
|
+
)
|
|
143
|
+
|
|
122
144
|
try:
|
|
123
145
|
items = _resolve_items(family, options)
|
|
124
146
|
except ValueError as exc:
|
|
@@ -126,18 +148,6 @@ def run_reset_command(kind: str, legacy_args: tuple[str, ...], paths) -> Command
|
|
|
126
148
|
if not items:
|
|
127
149
|
return CommandResult(0, f"Python {kind} reset", f"No {FAMILY_LABELS[kind]}s found with status: {options.filter_mode}")
|
|
128
150
|
|
|
129
|
-
if options.run_after and len(items) > 1:
|
|
130
|
-
options = ResetOptions(
|
|
131
|
-
list_path=options.list_path,
|
|
132
|
-
item_id=options.item_id,
|
|
133
|
-
item_range=options.item_range,
|
|
134
|
-
filter_mode=options.filter_mode,
|
|
135
|
-
clean=options.clean,
|
|
136
|
-
run_after=False,
|
|
137
|
-
help_requested=False,
|
|
138
|
-
unknown_args=options.unknown_args,
|
|
139
|
-
)
|
|
140
|
-
|
|
141
151
|
lines: list[str] = []
|
|
142
152
|
success = 0
|
|
143
153
|
failed = 0
|
|
@@ -155,14 +165,6 @@ def run_reset_command(kind: str, legacy_args: tuple[str, ...], paths) -> Command
|
|
|
155
165
|
failed += 1
|
|
156
166
|
|
|
157
167
|
lines.append(f"Reset complete: {success} succeeded, {failed} failed")
|
|
158
|
-
if options.run_after and len(items) == 1 and failed == 0:
|
|
159
|
-
from .runners import run_pipeline_command
|
|
160
|
-
|
|
161
|
-
lines.append(f"Auto-retrying {items[0].item_id} via Python foreground runner...")
|
|
162
|
-
retry_result = run_pipeline_command(kind, "run", (items[0].item_id, str(options.list_path)), paths)
|
|
163
|
-
lines.append(retry_result.render())
|
|
164
|
-
return CommandResult(retry_result.exit_code, f"Python {kind} reset", "\n".join(lines), stdout="\n".join(lines))
|
|
165
|
-
|
|
166
168
|
return CommandResult(0 if failed == 0 else 1, f"Python {kind} reset", "\n".join(lines), stdout="\n".join(lines))
|
|
167
169
|
|
|
168
170
|
|
|
@@ -173,7 +175,7 @@ def _parse_reset_args(family: RunnerFamily, legacy_args: Sequence[str]) -> Reset
|
|
|
173
175
|
item_range: tuple[str, str] | None = None
|
|
174
176
|
filter_mode = ""
|
|
175
177
|
clean = False
|
|
176
|
-
|
|
178
|
+
preserve_runtime = False
|
|
177
179
|
help_requested = False
|
|
178
180
|
unknown: list[str] = []
|
|
179
181
|
positional: list[str] = []
|
|
@@ -185,10 +187,19 @@ def _parse_reset_args(family: RunnerFamily, legacy_args: Sequence[str]) -> Reset
|
|
|
185
187
|
help_requested = True
|
|
186
188
|
elif arg == "--clean":
|
|
187
189
|
clean = True
|
|
190
|
+
elif arg == "--preserve-runtime":
|
|
191
|
+
preserve_runtime = True
|
|
188
192
|
elif arg == "--run":
|
|
189
|
-
|
|
193
|
+
raise ValueError(
|
|
194
|
+
"Reset no longer accepts --run. Run reset first, then execute "
|
|
195
|
+
f"`{family.kind} run` as a separate command."
|
|
196
|
+
)
|
|
190
197
|
elif arg in FILTER_FLAGS:
|
|
191
|
-
|
|
198
|
+
next_filter = FILTER_FLAGS[arg]
|
|
199
|
+
if filter_mode and filter_mode != next_filter:
|
|
200
|
+
unknown.append(arg)
|
|
201
|
+
else:
|
|
202
|
+
filter_mode = next_filter
|
|
192
203
|
elif arg.startswith("-"):
|
|
193
204
|
unknown.append(arg)
|
|
194
205
|
else:
|
|
@@ -211,12 +222,26 @@ def _parse_reset_args(family: RunnerFamily, legacy_args: Sequence[str]) -> Reset
|
|
|
211
222
|
item_range=item_range,
|
|
212
223
|
filter_mode=filter_mode,
|
|
213
224
|
clean=clean,
|
|
214
|
-
|
|
225
|
+
preserve_runtime=preserve_runtime,
|
|
215
226
|
help_requested=help_requested,
|
|
216
227
|
unknown_args=tuple(unknown),
|
|
217
228
|
)
|
|
218
229
|
|
|
219
230
|
|
|
231
|
+
def _reset_option_error(family: RunnerFamily, options: ResetOptions) -> str:
|
|
232
|
+
if options.unknown_args:
|
|
233
|
+
return "Unsupported reset arguments: " + " ".join(options.unknown_args)
|
|
234
|
+
if not options.preserve_runtime:
|
|
235
|
+
return ""
|
|
236
|
+
if options.filter_mode != "failed":
|
|
237
|
+
return "--preserve-runtime requires --failed and cannot be used with another reset filter."
|
|
238
|
+
if options.clean:
|
|
239
|
+
return "--preserve-runtime and --clean are mutually exclusive."
|
|
240
|
+
if options.item_id or options.item_range:
|
|
241
|
+
return "--preserve-runtime is a whole-list failed-chain reset and cannot target an ID or range."
|
|
242
|
+
return ""
|
|
243
|
+
|
|
244
|
+
|
|
220
245
|
def _resolve_list_path(path: Path, project_root: Path) -> Path:
|
|
221
246
|
return path.resolve() if path.is_absolute() else (project_root / path).resolve()
|
|
222
247
|
|
|
@@ -430,7 +455,9 @@ def _numeric_suffix(value: str, prefix: str) -> int:
|
|
|
430
455
|
def _help_text(family: RunnerFamily) -> str:
|
|
431
456
|
label = FAMILY_LABELS[family.kind]
|
|
432
457
|
return (
|
|
433
|
-
f"Usage: prizmkit-runtime reset {family.kind} <{label}-id|range> [--clean]
|
|
458
|
+
f"Usage: prizmkit-runtime reset {family.kind} <{label}-id|range> [--clean] "
|
|
434
459
|
"[--auto-skipped|--failed|--stalled] [list-path]\n"
|
|
435
|
-
"
|
|
460
|
+
f" prizmkit-runtime reset {family.kind} --failed --preserve-runtime [list-path]\n"
|
|
461
|
+
"Reset changes state only and never accepts --run; execute the matching family run command separately.\n"
|
|
462
|
+
"Standard/clean reset abandons the active checkout boundary. Preserve-runtime reset keeps task runtime and work."
|
|
436
463
|
)
|