prizmkit 1.1.156 → 1.1.160
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/adapters/codebuddy/settings-adapter.js +76 -25
- package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +9 -2
- package/bundled/dev-pipeline/prizmkit_runtime/reset.py +1 -1
- package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +20 -11
- package/bundled/dev-pipeline/prizmkit_runtime/runtime_commit.py +42 -15
- package/bundled/dev-pipeline/scripts/update-feature-status.py +7 -0
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +1 -1
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +1 -1
- package/bundled/dev-pipeline/templates/sections/runtime-commit-handoff.md +6 -6
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +4 -3
- package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +2 -2
- package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +2 -2
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +115 -4
- package/bundled/dev-pipeline/tests/test_reset_modes.py +137 -0
- package/bundled/dev-pipeline/tests/test_runtime_commit.py +68 -13
- package/bundled/dev-pipeline/tests/test_unified_cli.py +12 -7
- package/bundled/rules/prizm/prizm-commit-workflow.md +7 -7
- package/bundled/rules/prizm/prizm-documentation.md +24 -65
- package/bundled/rules/prizm/prizm-progressive-loading.md +9 -8
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/prizmkit/SKILL.md +1 -13
- package/bundled/skills/prizmkit-code-review/SKILL.md +29 -10
- package/bundled/skills/prizmkit-code-review/references/independent-code-review.md +5 -4
- package/bundled/skills/prizmkit-code-review/references/review-report-template.md +15 -0
- package/bundled/skills/prizmkit-code-review/scripts/render_review_report.py +61 -0
- package/bundled/skills/prizmkit-committer/SKILL.md +50 -38
- package/bundled/skills/prizmkit-deploy/SKILL.md +172 -198
- package/bundled/skills/prizmkit-deploy/references/capability-contract.md +137 -0
- package/bundled/skills/prizmkit-deploy/references/deploy-record-schema.json +1053 -0
- package/bundled/skills/prizmkit-deploy/references/deployment-declaration-schema.json +291 -0
- package/bundled/skills/prizmkit-deploy/references/legacy-migration.md +90 -0
- package/bundled/skills/prizmkit-deploy/references/policy-and-execution.md +170 -0
- package/bundled/skills/prizmkit-deploy/references/real-resource-test-policy.md +73 -0
- package/bundled/skills/prizmkit-deploy/references/verification-and-recovery.md +164 -0
- package/bundled/skills/prizmkit-deploy/scripts/validate-deploy-artifact.py +371 -0
- package/bundled/skills/prizmkit-implement/SKILL.md +2 -2
- package/bundled/skills/prizmkit-init/SKILL.md +38 -42
- package/bundled/skills/prizmkit-init/references/config-schema.md +11 -7
- package/bundled/skills/prizmkit-init/references/rules/layer-detection.md +3 -3
- package/bundled/skills/prizmkit-init/references/update-supplement.md +5 -5
- package/bundled/skills/prizmkit-plan/SKILL.md +5 -4
- package/bundled/skills/prizmkit-plan/assets/plan-template.md +4 -1
- package/bundled/skills/prizmkit-plan/references/verification-checklist.md +3 -2
- package/bundled/skills/prizmkit-prizm-docs/SKILL.md +17 -11
- package/bundled/skills/prizmkit-prizm-docs/assets/prizm-docs-format.md +95 -155
- package/bundled/skills/prizmkit-prizm-docs/references/op-init.md +6 -5
- package/bundled/skills/prizmkit-prizm-docs/references/op-rebuild.md +4 -2
- package/bundled/skills/prizmkit-prizm-docs/references/op-status.md +9 -10
- package/bundled/skills/prizmkit-prizm-docs/references/op-update.md +6 -5
- package/bundled/skills/prizmkit-prizm-docs/references/op-validate.md +13 -12
- package/bundled/skills/prizmkit-retrospective/SKILL.md +3 -3
- package/bundled/skills/prizmkit-test/SKILL.md +26 -13
- package/bundled/skills/prizmkit-test/references/boundary-contract-and-test-double-guidance.md +8 -4
- package/bundled/skills/prizmkit-test/references/independent-test-review.md +7 -3
- package/bundled/skills/prizmkit-test/references/test-coverage-model.md +33 -10
- package/bundled/skills/prizmkit-test/references/test-report-template.md +33 -11
- package/bundled/skills/prizmkit-workflow/SKILL.md +33 -3
- package/bundled/skills/prizmkit-workflow/references/workflow-state-protocol.md +23 -5
- package/bundled/templates/hooks/commit-intent-status.py +9 -41
- package/bundled/templates/hooks/commit-intent.json +3 -3
- package/bundled/templates/hooks/diff-prizm-docs.py +3 -1
- package/bundled/templates/hooks/prizm-pre-commit.py +32 -6
- package/bundled/templates/hooks/run-python-hook.cjs +44 -0
- package/bundled/templates/hooks/validate-prizm-docs.py +399 -173
- package/bundled/templates/project-memory-template.md +19 -19
- package/package.json +1 -1
- package/src/clean.js +6 -7
- package/src/gitignore-template.js +8 -12
- package/src/scaffold.js +125 -71
- package/bundled/skills/prizmkit/references/workflow-state-protocol.md +0 -178
- package/bundled/skills/prizmkit-deploy/assets/deploy-document-template.md +0 -89
- package/bundled/skills/prizmkit-deploy/references/ci-cd-workflows.md +0 -145
- package/bundled/skills/prizmkit-deploy/references/cloud-platform-deploy.md +0 -109
- package/bundled/skills/prizmkit-deploy/references/data-safety-examples.md +0 -120
- package/bundled/skills/prizmkit-deploy/references/database-setup.md +0 -65
- package/bundled/skills/prizmkit-deploy/references/deploy-config-schema.md +0 -150
- package/bundled/skills/prizmkit-deploy/references/deploy-history-schema.md +0 -78
- package/bundled/skills/prizmkit-deploy/references/deploy-metadata-schema.json +0 -49
- package/bundled/skills/prizmkit-deploy/references/deployment-modes.md +0 -50
- package/bundled/skills/prizmkit-deploy/references/direct-upload.md +0 -26
- package/bundled/skills/prizmkit-deploy/references/dns-setup.md +0 -42
- package/bundled/skills/prizmkit-deploy/references/docker-deploy.md +0 -31
- package/bundled/skills/prizmkit-deploy/references/firewall-setup.md +0 -37
- package/bundled/skills/prizmkit-deploy/references/live-validation-notes.md +0 -21
- package/bundled/skills/prizmkit-deploy/references/nginx-blue-green.md +0 -59
- package/bundled/skills/prizmkit-deploy/references/pending-input-schema.json +0 -164
- package/bundled/skills/prizmkit-deploy/references/ssh-adapter-flow.md +0 -221
- package/bundled/skills/prizmkit-deploy/references/ssh-bootstrap-flow.md +0 -49
- package/bundled/skills/prizmkit-deploy/references/ssh-execution-flow.md +0 -41
- package/bundled/skills/prizmkit-deploy/references/ssh-takeover.md +0 -20
- package/bundled/skills/prizmkit-deploy/references/ssl-setup.md +0 -56
package/bundled/VERSION.json
CHANGED
|
@@ -1,15 +1,78 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CodeBuddy
|
|
3
|
-
*
|
|
2
|
+
* CodeBuddy settings adapter.
|
|
3
|
+
* Replaces only deterministic PrizmKit-managed hook entries and preserves user settings.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { existsSync, mkdirSync } from 'node:fs';
|
|
7
7
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
8
|
-
import path from 'path';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
|
|
10
|
+
const MANAGED_MARKERS = [
|
|
11
|
+
'.prizmkit/scripts/commit-intent-status.py',
|
|
12
|
+
'.prizmkit/scripts/post-command-prizm-drift.py',
|
|
13
|
+
'PRIZMKIT_DOC_UPDATE_REQUIRED',
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
function isManaged(entry) {
|
|
17
|
+
let serialized;
|
|
18
|
+
try {
|
|
19
|
+
serialized = JSON.stringify(entry);
|
|
20
|
+
} catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return MANAGED_MARKERS.some(marker => serialized.includes(marker));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function mergeManagedHooks(existingHooks = {}, managedHooks = {}) {
|
|
27
|
+
if (!existingHooks || typeof existingHooks !== 'object' || Array.isArray(existingHooks)) {
|
|
28
|
+
throw new Error('Cannot preserve malformed CodeBuddy hooks: hooks must be an object');
|
|
29
|
+
}
|
|
30
|
+
const merged = {};
|
|
31
|
+
for (const [event, entries] of Object.entries(existingHooks)) {
|
|
32
|
+
if (!Array.isArray(entries)) {
|
|
33
|
+
throw new Error(`Cannot preserve malformed CodeBuddy hooks: ${event} must be an array`);
|
|
34
|
+
}
|
|
35
|
+
merged[event] = entries.filter(entry => !isManaged(entry));
|
|
36
|
+
}
|
|
37
|
+
for (const [event, entries] of Object.entries(managedHooks)) {
|
|
38
|
+
if (!Array.isArray(entries)) {
|
|
39
|
+
throw new Error(`Managed CodeBuddy hook template is invalid: ${event} must be an array`);
|
|
40
|
+
}
|
|
41
|
+
merged[event] = [
|
|
42
|
+
...(Array.isArray(merged[event]) ? merged[event] : []),
|
|
43
|
+
...entries,
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
return merged;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const MANAGED_HOOKS = {
|
|
50
|
+
UserPromptSubmit: [
|
|
51
|
+
{
|
|
52
|
+
matcher: '(?i)\\b(commit|push|finish|ship|merge|pull request|pr)\\b|提交|推送|收尾|完成任务|合并|发版|发布',
|
|
53
|
+
hooks: [
|
|
54
|
+
{
|
|
55
|
+
type: 'command',
|
|
56
|
+
command: 'node .prizmkit/scripts/run-python-hook.cjs .prizmkit/scripts/commit-intent-status.py',
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
PostToolUse: [
|
|
62
|
+
{
|
|
63
|
+
matcher: '.*',
|
|
64
|
+
hooks: [
|
|
65
|
+
{
|
|
66
|
+
type: 'command',
|
|
67
|
+
command: 'node .prizmkit/scripts/run-python-hook.cjs .prizmkit/scripts/post-command-prizm-drift.py',
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
9
73
|
|
|
10
74
|
/**
|
|
11
|
-
*
|
|
12
|
-
* @param {string} targetRoot - Target project root
|
|
75
|
+
* @param {string} targetRoot
|
|
13
76
|
* @param {Object} options - { hooks: boolean }
|
|
14
77
|
*/
|
|
15
78
|
export async function generateSettings(targetRoot, options = {}) {
|
|
@@ -20,28 +83,16 @@ export async function generateSettings(targetRoot, options = {}) {
|
|
|
20
83
|
if (existsSync(settingsPath)) {
|
|
21
84
|
try {
|
|
22
85
|
existing = JSON.parse(await readFile(settingsPath, 'utf8'));
|
|
23
|
-
} catch {
|
|
24
|
-
|
|
86
|
+
} catch (error) {
|
|
87
|
+
throw new Error(`Cannot preserve malformed CodeBuddy settings: ${error.message}`);
|
|
25
88
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// Merge PrizmKit hooks
|
|
29
|
-
if (options.hooks !== false) {
|
|
30
|
-
if (!existing.hooks) existing.hooks = {};
|
|
31
|
-
if (!existing.hooks.UserPromptSubmit) {
|
|
32
|
-
existing.hooks.UserPromptSubmit = [
|
|
33
|
-
{
|
|
34
|
-
matcher: '(?i)\\b(commit|push|finish|ship|merge|pull request|pr)\\b|提交|推送|收尾|完成任务|合并|发版|发布',
|
|
35
|
-
hooks: [
|
|
36
|
-
{
|
|
37
|
-
type: 'prompt',
|
|
38
|
-
prompt: 'You are a commit-intent detector for PrizmKit. Analyze the user prompt and determine if the user intends to COMMIT, PUSH, FINISH, SHIP, MERGE, or create a PULL REQUEST.\n\nUser prompt: $ARGUMENTS\n\nIF commit intent detected, respond with:\n{"ok": true, "reason": "PRIZMKIT_DOC_UPDATE_REQUIRED: Before committing, you MUST update .prizmkit/prizm-docs/ per Prizm auto-update protocol. Steps: 1) Run git diff --cached --name-status. 2) Map changed files to modules via root.prizm MODULE_INDEX. 3) Read and update affected .prizm files (only changed sections). 4) Append to changelog.prizm. 5) Stage .prizm files with git add .prizmkit/prizm-docs/. 6) Then proceed with commit using prizmkit-committer workflow. RULES: Never rewrite entire .prizm files. Never add prose. Only update affected sections."}\n\nIF no commit intent, respond with:\n{"ok": true}\n\nRespond with JSON only. No explanation.',
|
|
39
|
-
},
|
|
40
|
-
],
|
|
41
|
-
},
|
|
42
|
-
];
|
|
89
|
+
if (!existing || typeof existing !== 'object' || Array.isArray(existing)) {
|
|
90
|
+
throw new Error('Cannot preserve malformed CodeBuddy settings: root must be an object');
|
|
43
91
|
}
|
|
44
92
|
}
|
|
45
93
|
|
|
46
|
-
|
|
94
|
+
const settings = options.hooks === false
|
|
95
|
+
? existing
|
|
96
|
+
: { ...existing, hooks: mergeManagedHooks(existing.hooks, MANAGED_HOOKS) };
|
|
97
|
+
await writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
47
98
|
}
|
|
@@ -17,8 +17,15 @@ PIPELINE_METADATA_EXCLUDES = (
|
|
|
17
17
|
":(top,exclude,glob).*/worktree/**",
|
|
18
18
|
":(top,exclude,glob).*/worktrees",
|
|
19
19
|
":(top,exclude,glob).*/worktrees/**",
|
|
20
|
-
":(top,exclude).prizmkit",
|
|
21
|
-
":(top,exclude,glob).prizmkit/**",
|
|
20
|
+
":(top,exclude).prizmkit/dev-pipeline",
|
|
21
|
+
":(top,exclude,glob).prizmkit/dev-pipeline/**",
|
|
22
|
+
":(top,exclude).prizmkit/state",
|
|
23
|
+
":(top,exclude,glob).prizmkit/state/**",
|
|
24
|
+
":(top,exclude).prizmkit/scripts",
|
|
25
|
+
":(top,exclude,glob).prizmkit/scripts/**",
|
|
26
|
+
":(top,exclude).prizmkit/manifest.json",
|
|
27
|
+
":(top,exclude,glob).prizmkit/specs/**/workflow-checkpoint.json",
|
|
28
|
+
":(top,exclude,glob).prizmkit/specs/**/runtime-commit-request.json",
|
|
22
29
|
)
|
|
23
30
|
|
|
24
31
|
HIDDEN_TOOL_WORKTREE_EXCLUDES = (
|
|
@@ -115,7 +115,7 @@ def run_reset_command(kind: str, legacy_args: tuple[str, ...], paths) -> Command
|
|
|
115
115
|
list_path = _resolve_list_path(options.list_path, paths.project_root)
|
|
116
116
|
if not list_path.is_file():
|
|
117
117
|
return CommandResult(1, f"Python {kind} reset", f"{kind} list not found: {list_path}")
|
|
118
|
-
if
|
|
118
|
+
if options.fresh_checkout and not (family.state_dir / "pipeline.json").is_file():
|
|
119
119
|
return CommandResult(1, f"Python {kind} reset", f"No pipeline state found. Run the {kind} pipeline first to initialize.")
|
|
120
120
|
|
|
121
121
|
options = ResetOptions(
|
|
@@ -92,17 +92,7 @@ def classify_session(
|
|
|
92
92
|
)
|
|
93
93
|
|
|
94
94
|
semantic = checkpoint.semantic_snapshot if checkpoint is not None else {}
|
|
95
|
-
if
|
|
96
|
-
reason = "no_semantic_completion"
|
|
97
|
-
if checkpoint is not None and checkpoint.semantic.error_code:
|
|
98
|
-
reason = f"{reason}:{checkpoint.semantic.error_code}"
|
|
99
|
-
return SessionClassification(
|
|
100
|
-
WORKFLOW_SKIPPED,
|
|
101
|
-
reason=reason,
|
|
102
|
-
progress_fingerprint=fingerprint,
|
|
103
|
-
checkpoint_state=semantic,
|
|
104
|
-
)
|
|
105
|
-
if _is_context_overflow(result):
|
|
95
|
+
if _is_recoverable_context_interruption(result):
|
|
106
96
|
no_progress_count = _next_no_progress_count(previous_fingerprint, fingerprint, previous_no_progress_count)
|
|
107
97
|
if no_progress_count >= 2:
|
|
108
98
|
return SessionClassification(
|
|
@@ -121,6 +111,16 @@ def classify_session(
|
|
|
121
111
|
no_progress_count=no_progress_count,
|
|
122
112
|
checkpoint_state=semantic,
|
|
123
113
|
)
|
|
114
|
+
if _is_terminal_success(result):
|
|
115
|
+
reason = "no_semantic_completion"
|
|
116
|
+
if checkpoint is not None and checkpoint.semantic.error_code:
|
|
117
|
+
reason = f"{reason}:{checkpoint.semantic.error_code}"
|
|
118
|
+
return SessionClassification(
|
|
119
|
+
WORKFLOW_SKIPPED,
|
|
120
|
+
reason=reason,
|
|
121
|
+
progress_fingerprint=fingerprint,
|
|
122
|
+
checkpoint_state=semantic,
|
|
123
|
+
)
|
|
124
124
|
|
|
125
125
|
if result.termination_reason == "stale_session":
|
|
126
126
|
return SessionClassification(
|
|
@@ -275,6 +275,15 @@ def _next_no_progress_count(previous: object | None, current: object, count: int
|
|
|
275
275
|
return 0
|
|
276
276
|
|
|
277
277
|
|
|
278
|
+
def _is_recoverable_context_interruption(result: AISessionResult) -> bool:
|
|
279
|
+
"""Recognize provider limits that should continue an incomplete workflow."""
|
|
280
|
+
if _is_terminal_success(result):
|
|
281
|
+
# Pi reports a provider token/length limit as a successful result event.
|
|
282
|
+
# Semantic completion was already handled before this helper is called.
|
|
283
|
+
return result.progress_summary.stop_reason.strip().lower() == "length"
|
|
284
|
+
return _is_context_overflow(result)
|
|
285
|
+
|
|
286
|
+
|
|
278
287
|
def _is_context_overflow(result: AISessionResult) -> bool:
|
|
279
288
|
if (result.fatal_error_code or "").lower() == CONTEXT_OVERFLOW:
|
|
280
289
|
return True
|
|
@@ -106,9 +106,9 @@ def finalize_runtime_commit(
|
|
|
106
106
|
return RuntimeCommitResult("not_ready", "runtime_commit_already_finalized")
|
|
107
107
|
return RuntimeCommitResult("failed", error or "invalid_commit_request")
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
# Request/checkpoint paths are excluded by their exact Runtime bookkeeping role.
|
|
110
|
+
# They may be project-tracked; commit verification below ensures their pre/post-
|
|
111
|
+
# commit writes never enter the prepared snapshot.
|
|
112
112
|
current_head = _git(root, "rev-parse", "HEAD")
|
|
113
113
|
if current_head.return_code != 0:
|
|
114
114
|
return RuntimeCommitResult("failed", "git_head_unavailable")
|
|
@@ -133,7 +133,15 @@ def finalize_runtime_commit(
|
|
|
133
133
|
staged = _stage_intended_paths(root, request.intended_paths)
|
|
134
134
|
if staged.return_code != 0:
|
|
135
135
|
return RuntimeCommitResult("failed", "git_stage_failed")
|
|
136
|
-
|
|
136
|
+
staged_paths = _git(
|
|
137
|
+
root, "diff", "--cached", "--name-only", "--no-renames", "-z",
|
|
138
|
+
)
|
|
139
|
+
if staged_paths.return_code != 0:
|
|
140
|
+
return RuntimeCommitResult("failed", "git_staged_set_unavailable")
|
|
141
|
+
staged_set = {path for path in staged_paths.stdout.split("\0") if path}
|
|
142
|
+
if staged_set != set(request.intended_paths):
|
|
143
|
+
return RuntimeCommitResult("failed", "staged_paths_mismatch")
|
|
144
|
+
if not staged_set:
|
|
137
145
|
return RuntimeCommitResult("failed", "empty_staged_change")
|
|
138
146
|
committed = _git(
|
|
139
147
|
root,
|
|
@@ -320,7 +328,21 @@ def _known_support_path(lower_path: str) -> bool:
|
|
|
320
328
|
and parts[1] in {"worktree", "worktrees"}
|
|
321
329
|
):
|
|
322
330
|
return True
|
|
323
|
-
|
|
331
|
+
if lower_path in {".prizmkit/manifest.json"}:
|
|
332
|
+
return True
|
|
333
|
+
if any(
|
|
334
|
+
lower_path == prefix or lower_path.startswith(prefix + "/")
|
|
335
|
+
for prefix in (
|
|
336
|
+
".prizmkit/dev-pipeline",
|
|
337
|
+
".prizmkit/state",
|
|
338
|
+
".prizmkit/scripts",
|
|
339
|
+
)
|
|
340
|
+
):
|
|
341
|
+
return True
|
|
342
|
+
return (
|
|
343
|
+
lower_path.startswith(".prizmkit/specs/")
|
|
344
|
+
and path.name in {REQUEST_FILENAME, "workflow-checkpoint.json"}
|
|
345
|
+
)
|
|
324
346
|
|
|
325
347
|
|
|
326
348
|
def _status_record_paths(stdout: str) -> tuple[str, ...]:
|
|
@@ -342,8 +364,21 @@ def _status_record_paths(stdout: str) -> tuple[str, ...]:
|
|
|
342
364
|
|
|
343
365
|
|
|
344
366
|
def _stage_intended_paths(project_root: Path, paths: Sequence[str]) -> _GitResult:
|
|
345
|
-
|
|
346
|
-
|
|
367
|
+
tracked: list[str] = []
|
|
368
|
+
untracked: list[str] = []
|
|
369
|
+
for path in paths:
|
|
370
|
+
pathspec = f":(top,literal){path}"
|
|
371
|
+
indexed = _git(project_root, "ls-files", "--error-unmatch", "--", pathspec)
|
|
372
|
+
(tracked if indexed.return_code == 0 else untracked).append(pathspec)
|
|
373
|
+
if tracked:
|
|
374
|
+
updated = _git(project_root, "add", "-u", "--", *tracked)
|
|
375
|
+
if updated.return_code != 0:
|
|
376
|
+
return updated
|
|
377
|
+
if untracked:
|
|
378
|
+
added = _git(project_root, "add", "--", *untracked)
|
|
379
|
+
if added.return_code != 0:
|
|
380
|
+
return added
|
|
381
|
+
return _GitResult(0, "", "")
|
|
347
382
|
|
|
348
383
|
|
|
349
384
|
def _matches_prepared_commit(project_root: Path, request: RuntimeCommitRequest, head: str) -> bool:
|
|
@@ -378,14 +413,6 @@ def _record_runtime_commit_hash(path: Path, commit_hash: str) -> str:
|
|
|
378
413
|
return "commit_request_hash_record_failed" if error else ""
|
|
379
414
|
|
|
380
415
|
|
|
381
|
-
def _is_tracked(project_root: Path, path: Path) -> bool:
|
|
382
|
-
try:
|
|
383
|
-
relative = path.relative_to(project_root).as_posix()
|
|
384
|
-
except ValueError:
|
|
385
|
-
return True
|
|
386
|
-
return _git(project_root, "ls-files", "--error-unmatch", "--", relative).return_code == 0
|
|
387
|
-
|
|
388
|
-
|
|
389
416
|
def _finalize_checkpoint(
|
|
390
417
|
path: Path,
|
|
391
418
|
*,
|
|
@@ -1726,6 +1726,13 @@ def action_clean(args, feature_list_path, state_dir):
|
|
|
1726
1726
|
fs["last_session_id"] = None
|
|
1727
1727
|
fs["resume_from_phase"] = None
|
|
1728
1728
|
reset_continuation_metadata(fs)
|
|
1729
|
+
for stale_field in (
|
|
1730
|
+
"repair_scope",
|
|
1731
|
+
"repair_round",
|
|
1732
|
+
"blocked_reason",
|
|
1733
|
+
"terminal_status",
|
|
1734
|
+
):
|
|
1735
|
+
fs.pop(stale_field, None)
|
|
1729
1736
|
fs["updated_at"] = now_iso()
|
|
1730
1737
|
|
|
1731
1738
|
err = save_feature_status(state_dir, feature_id, fs)
|
|
@@ -38,7 +38,7 @@ Complete the feature in headless non-interactive mode using the active atomic sk
|
|
|
38
38
|
5. Invoke `/prizmkit-test scope=this-change artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/`. Validate its report/result pair. For `TEST_NEEDS_FIXES`, classify the concrete correction into an allowed `repair_scope`; unknown/unsafe scope blocks, while a safe in-budget route re-enters Implement and requires fresh Review, configured verification, and Test. Do not duplicate the Skill's internal repair loop.
|
|
39
39
|
6. Write `completion-summary.json` before retrospective and commit preparation.
|
|
40
40
|
7. Invoke `/prizmkit-retrospective` with the exact artifact root, non-`.prizmkit/` `change_paths`, and `change_summary`; validate `outcome=RETRO_COMPLETE`.
|
|
41
|
-
8. Before commit preparation,
|
|
41
|
+
8. Before commit preparation, classify paths by semantic role rather than a blanket `.prizmkit/**` rule. Safe Git-visible framework paths may be exact task output; ignored paths remain absent, and exact Runtime bookkeeping/installed support, host support, Secrets, unrelated, or unknown paths remain excluded or blocking. No path is force-added and no ignore policy is changed. After validating every required artifact, invoke `/prizmkit-committer operation=prepare-runtime-commit artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/ evidence_paths=<exact paths> excluded_paths=.prizmkit/specs/{{FEATURE_SLUG}}/workflow-checkpoint.json request_path=.prizmkit/specs/{{FEATURE_SLUG}}/runtime-commit-request.json`. Require `COMMIT_REQUEST_READY`; this session then records `COMMIT_PENDING` and stops. The Python runtime executes and verifies the local commit.
|
|
42
42
|
|
|
43
43
|
## Failure Capture
|
|
44
44
|
|
|
@@ -448,7 +448,7 @@ Invoke `/prizmkit-retrospective` with the exact artifact root, exact non-`.prizm
|
|
|
448
448
|
|
|
449
449
|
**6c. Runtime commit preparation**
|
|
450
450
|
|
|
451
|
-
Before commit preparation,
|
|
451
|
+
Before commit preparation, classify paths by semantic role rather than a blanket `.prizmkit/**` exclusion. Safe Git-visible framework paths may be justified and included as exact task output; ignored paths remain naturally absent. Exact Runtime request/checkpoint/state and installed Runtime/host support stay outside `intended_paths`; Secrets, unrelated, and unknown Git-visible paths block. Never force-add or change/interpret project ignore policy.
|
|
452
452
|
|
|
453
453
|
After this injected session validates every required artifact, invoke `/prizmkit-committer operation=prepare-runtime-commit artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/ evidence_paths=<exact paths> excluded_paths=.prizmkit/specs/{{FEATURE_SLUG}}/workflow-checkpoint.json request_path=.prizmkit/specs/{{FEATURE_SLUG}}/runtime-commit-request.json`. Require `COMMIT_REQUEST_READY`; this session records `COMMIT_PENDING` and stops. The Python runtime validates the request, executes/verifies the local commit, and finalizes checkpoint `COMMITTED`.
|
|
454
454
|
|
|
@@ -11,11 +11,11 @@ After Code Review, all configured verification, `TEST_PASS`, family reports/summ
|
|
|
11
11
|
/prizmkit-committer operation=prepare-runtime-commit artifact_dir={{ARTIFACT_DIR}} evidence_paths=<exact validated artifact paths> excluded_paths={{ARTIFACT_DIR}}/workflow-checkpoint.json request_path={{ARTIFACT_DIR}}/runtime-commit-request.json
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
3. The committer validates only the supplied evidence and final diff, then classifies paths before writing the request:
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
14
|
+
3. The committer validates only the supplied evidence and final diff, then classifies paths by semantic role before writing the request:
|
|
15
|
+
- safe Git-visible `.prizmkit/**` requirement output is admitted like any other exact task path and needs no documentation-specific evidence;
|
|
16
|
+
- ignored paths remain absent and are never force-added; project ignore policy is not changed or interpreted;
|
|
17
|
+
- exact Runtime request/checkpoint/state, installed Runtime/host payloads, and local host settings remain support/bookkeeping outside the task commit;
|
|
18
|
+
- global Secret checks still apply, and every unrelated or unknown Git-visible path blocks rather than disappearing.
|
|
19
19
|
|
|
20
20
|
It then rejects sensitive/unrelated/unknown paths, generates one Conventional Commit message, and writes this request without staging or committing:
|
|
21
21
|
|
|
@@ -32,4 +32,4 @@ After Code Review, all configured verification, `TEST_PASS`, family reports/summ
|
|
|
32
32
|
4. Require the stage-local result `COMMIT_REQUEST_READY`. Then this injected session—not the Skill—marks `prizmkit-committer` `in_progress` with `stage_result=COMMIT_PENDING` through the checkpoint helper. Do not mark it completed or write `COMMITTED`.
|
|
33
33
|
5. Stop normal work after the valid request and checkpoint handoff exist. Do not run `git add`, `git commit`, `git commit --amend`, merge, push, or create additional files.
|
|
34
34
|
|
|
35
|
-
The
|
|
35
|
+
The Runtime validates exact task-owned path coverage outside recognized semantic support/bookkeeping, does not reject a safe path solely because it is under `.prizmkit/**`, stages only requested literal paths, verifies staged/committed set equality and the Git receipt, and only then writes the Runtime-owned receipt/checkpoint and performs configured integration. Those post-commit writes are never inserted retroactively into the committed snapshot or allowed to falsify integration. Unknown Git-visible paths are not silently ignored: they produce a mismatch and preserve the task checkout for recovery. A malformed, stale, unsafe, incomplete, or contradictory request also blocks without deleting user data.
|
|
@@ -1556,9 +1556,10 @@ class TestFeatureBootstrapShellExtraction:
|
|
|
1556
1556
|
assert "/prizmkit-committer operation=prepare-runtime-commit" in tier3
|
|
1557
1557
|
assert "Require `COMMIT_REQUEST_READY`; this session records `COMMIT_PENDING`" in tier3
|
|
1558
1558
|
assert "The Python runtime validates the request" in tier3
|
|
1559
|
-
assert "
|
|
1560
|
-
assert "
|
|
1561
|
-
assert "
|
|
1559
|
+
assert "classify paths by semantic role rather than a blanket `.prizmkit/**` exclusion" in tier3
|
|
1560
|
+
assert "Safe Git-visible framework paths" in tier3
|
|
1561
|
+
assert "Never force-add or change/interpret project ignore policy" in tier3
|
|
1562
|
+
assert "unknown Git-visible paths block" in tier3
|
|
1562
1563
|
assert "git add" not in tier3
|
|
1563
1564
|
assert "git commit" not in tier3
|
|
1564
1565
|
|
|
@@ -596,8 +596,8 @@ class TestBugfixCheckpointGeneration:
|
|
|
596
596
|
assert "operation=prepare-runtime-commit" in prompt
|
|
597
597
|
assert "NEVER ask for user confirmation" in prompt
|
|
598
598
|
assert "The Python runtime, not the AI session, executes" in prompt
|
|
599
|
-
assert "
|
|
600
|
-
assert "
|
|
599
|
+
assert "safe Git-visible `.prizmkit/**` requirement output is admitted" in prompt
|
|
600
|
+
assert "unknown Git-visible path blocks" in prompt
|
|
601
601
|
assert "push_authorized\": true" not in prompt
|
|
602
602
|
assert ".prizmkit/bugfix/B-001/" in prompt
|
|
603
603
|
assert "write the session status" not in prompt.lower()
|
|
@@ -435,8 +435,8 @@ class TestRefactorCheckpointGeneration:
|
|
|
435
435
|
assert "local_commit_authorized" not in prompt
|
|
436
436
|
assert "operation=prepare-runtime-commit" in prompt
|
|
437
437
|
assert "The Python runtime, not the AI session, executes" in prompt
|
|
438
|
-
assert "
|
|
439
|
-
assert "
|
|
438
|
+
assert "safe Git-visible `.prizmkit/**` requirement output is admitted" in prompt
|
|
439
|
+
assert "unknown Git-visible path blocks" in prompt
|
|
440
440
|
assert "automatic push" not in prompt.lower()
|
|
441
441
|
assert "push_authorized\": true" not in prompt
|
|
442
442
|
assert "write the session status" not in prompt.lower()
|
|
@@ -4015,7 +4015,7 @@ def test_pi_length_stop_with_nonzero_exit_uses_bounded_crash_path(tmp_path):
|
|
|
4015
4015
|
assert classification.fatal_error_code == ""
|
|
4016
4016
|
|
|
4017
4017
|
|
|
4018
|
-
def
|
|
4018
|
+
def test_pi_length_stop_with_zero_exit_and_no_checkpoint_uses_recoverable_continuation(tmp_path):
|
|
4019
4019
|
from dataclasses import replace
|
|
4020
4020
|
|
|
4021
4021
|
from prizmkit_runtime.runner_classification import classify_session
|
|
@@ -4029,9 +4029,120 @@ def test_pi_length_stop_with_zero_exit_and_no_checkpoint_uses_no_completion_poli
|
|
|
4029
4029
|
|
|
4030
4030
|
classification = classify_session(raw, project_root=tmp_path, base_head=base_head)
|
|
4031
4031
|
|
|
4032
|
-
assert classification.session_status == "
|
|
4033
|
-
assert classification.reason == "
|
|
4034
|
-
assert classification.fatal_error_code == ""
|
|
4032
|
+
assert classification.session_status == "context_overflow"
|
|
4033
|
+
assert classification.reason == "context_overflow"
|
|
4034
|
+
assert classification.fatal_error_code == "context_overflow"
|
|
4035
|
+
|
|
4036
|
+
|
|
4037
|
+
def test_pi_length_stop_with_in_progress_checkpoint_uses_recoverable_continuation(tmp_path):
|
|
4038
|
+
from dataclasses import replace
|
|
4039
|
+
|
|
4040
|
+
from prizmkit_runtime.runner_classification import classify_session
|
|
4041
|
+
from prizmkit_runtime.runner_models import PromptGenerationResult
|
|
4042
|
+
from prizmkit_runtime.status import ProgressSummary
|
|
4043
|
+
|
|
4044
|
+
base_head = _init_git_repo_for_invalid_checkpoint_test(tmp_path)
|
|
4045
|
+
artifact_dir = tmp_path / ".prizmkit" / "specs" / "001-length-in-progress"
|
|
4046
|
+
artifact_dir.mkdir(parents=True)
|
|
4047
|
+
checkpoint = artifact_dir / "workflow-checkpoint.json"
|
|
4048
|
+
checkpoint.write_text(
|
|
4049
|
+
json.dumps({
|
|
4050
|
+
"version": 1,
|
|
4051
|
+
"workflow_type": "feature-pipeline",
|
|
4052
|
+
"steps": [
|
|
4053
|
+
{
|
|
4054
|
+
"id": "S01",
|
|
4055
|
+
"skill": "context-snapshot-and-plan",
|
|
4056
|
+
"name": "Specify & Plan",
|
|
4057
|
+
"status": "completed",
|
|
4058
|
+
"required_artifacts": [],
|
|
4059
|
+
"depends_on": None,
|
|
4060
|
+
"stage_result": "PLAN_READY",
|
|
4061
|
+
},
|
|
4062
|
+
{
|
|
4063
|
+
"id": "S02",
|
|
4064
|
+
"skill": "prizmkit-implement",
|
|
4065
|
+
"name": "Implement",
|
|
4066
|
+
"status": "completed",
|
|
4067
|
+
"required_artifacts": [],
|
|
4068
|
+
"depends_on": "S01",
|
|
4069
|
+
"stage_result": "IMPLEMENTED",
|
|
4070
|
+
},
|
|
4071
|
+
{
|
|
4072
|
+
"id": "S03",
|
|
4073
|
+
"skill": "prizmkit-code-review",
|
|
4074
|
+
"name": "Code Review",
|
|
4075
|
+
"status": "in_progress",
|
|
4076
|
+
"required_artifacts": [],
|
|
4077
|
+
"depends_on": "S02",
|
|
4078
|
+
},
|
|
4079
|
+
{
|
|
4080
|
+
"id": "S04",
|
|
4081
|
+
"skill": "prizmkit-test",
|
|
4082
|
+
"name": "Test",
|
|
4083
|
+
"status": "pending",
|
|
4084
|
+
"required_artifacts": [],
|
|
4085
|
+
"depends_on": "S03",
|
|
4086
|
+
},
|
|
4087
|
+
{
|
|
4088
|
+
"id": "S05",
|
|
4089
|
+
"skill": "completion-summary",
|
|
4090
|
+
"name": "Completion Summary",
|
|
4091
|
+
"status": "pending",
|
|
4092
|
+
"required_artifacts": [],
|
|
4093
|
+
"depends_on": "S04",
|
|
4094
|
+
},
|
|
4095
|
+
{
|
|
4096
|
+
"id": "S06",
|
|
4097
|
+
"skill": "prizmkit-retrospective",
|
|
4098
|
+
"name": "Retrospective",
|
|
4099
|
+
"status": "pending",
|
|
4100
|
+
"required_artifacts": [],
|
|
4101
|
+
"depends_on": "S05",
|
|
4102
|
+
},
|
|
4103
|
+
{
|
|
4104
|
+
"id": "S07",
|
|
4105
|
+
"skill": "prizmkit-committer",
|
|
4106
|
+
"name": "Runtime Commit Handoff",
|
|
4107
|
+
"status": "pending",
|
|
4108
|
+
"required_artifacts": [],
|
|
4109
|
+
"depends_on": "S06",
|
|
4110
|
+
},
|
|
4111
|
+
],
|
|
4112
|
+
"feature_state": {
|
|
4113
|
+
"stage": "code-review",
|
|
4114
|
+
"current_stage": "prizmkit-code-review",
|
|
4115
|
+
"status": "in_progress",
|
|
4116
|
+
"repair_scope": None,
|
|
4117
|
+
"repair_round": 0,
|
|
4118
|
+
"next_stage": "prizmkit-code-review",
|
|
4119
|
+
"blocked_reason": None,
|
|
4120
|
+
"terminal_status": None,
|
|
4121
|
+
},
|
|
4122
|
+
}),
|
|
4123
|
+
encoding="utf-8",
|
|
4124
|
+
)
|
|
4125
|
+
prompt = PromptGenerationResult(
|
|
4126
|
+
output_path=tmp_path / "prompt.md",
|
|
4127
|
+
checkpoint_path=checkpoint,
|
|
4128
|
+
artifact_path=artifact_dir,
|
|
4129
|
+
)
|
|
4130
|
+
raw = replace(
|
|
4131
|
+
_terminal_success_result(tmp_path),
|
|
4132
|
+
progress_summary=ProgressSummary(result_subtype="success", stop_reason="length"),
|
|
4133
|
+
)
|
|
4134
|
+
|
|
4135
|
+
classification = classify_session(
|
|
4136
|
+
raw,
|
|
4137
|
+
project_root=tmp_path,
|
|
4138
|
+
base_head=base_head,
|
|
4139
|
+
prompt=prompt,
|
|
4140
|
+
)
|
|
4141
|
+
|
|
4142
|
+
assert classification.session_status == "context_overflow"
|
|
4143
|
+
assert classification.reason == "context_overflow"
|
|
4144
|
+
assert classification.fatal_error_code == "context_overflow"
|
|
4145
|
+
assert classification.checkpoint_state["current_stage"] == "prizmkit-code-review"
|
|
4035
4146
|
|
|
4036
4147
|
|
|
4037
4148
|
def test_pi_length_stop_does_not_override_completed_checkpoint(tmp_path):
|