agent-project-sdlc 0.1.22 → 0.1.23
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/README.md +10 -4
- package/assets/docs/README.md +11 -5
- package/assets/policies/phase_contracts.yaml +128 -12
- package/assets/skills/pjsdlc_architect_design/SKILL.md +3 -1
- package/assets/skills/pjsdlc_dev_sprint/SKILL.md +6 -5
- package/assets/skills/pjsdlc_implementation_doc/SKILL.md +5 -4
- package/assets/skills/pjsdlc_reviewer/SKILL.md +2 -2
- package/assets/skills/pjsdlc_rfc_recalibrate/SKILL.md +3 -3
- package/assets/skills/pjsdlc_tester/SKILL.md +3 -3
- package/assets/templates/EVIDENCE_INDEX_TEMPLATE.md +2 -1
- package/assets/templates/EXPLORATION_APPENDIX_TEMPLATE.md +2 -0
- package/assets/templates/IMPLEMENTATION_DOC_TEMPLATE.md +27 -6
- package/assets/templates/PLAN_TEMPLATE.yaml +31 -1
- package/assets/templates/RUNBOOK_TEMPLATE.md +10 -5
- package/assets/tools/harness_utils.py +388 -18
- package/assets/tools/transition.py +24 -31
- package/assets/tools/validate_design.py +5 -0
- package/assets/tools/validate_harness.py +14 -1
- package/assets/tools/validate_prompt_language.py +1 -1
- package/assets/tools/validate_rfc.py +5 -0
- package/dist/lib/init.js +1 -1
- package/dist/lib/validators.js +567 -6
- package/package.json +1 -1
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
from harness_utils import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
targets.append(str(next_phase))
|
|
13
|
-
for return_phase in phase.get("returns") or []:
|
|
14
|
-
if return_phase:
|
|
15
|
-
targets.append(str(return_phase))
|
|
16
|
-
return list(dict.fromkeys(targets))
|
|
2
|
+
from harness_utils import (
|
|
3
|
+
dump_yaml,
|
|
4
|
+
find_phase_transition,
|
|
5
|
+
load_lifecycle,
|
|
6
|
+
load_phase_contract_data,
|
|
7
|
+
make_arg_parser,
|
|
8
|
+
phase_transition_targets,
|
|
9
|
+
require,
|
|
10
|
+
run_main,
|
|
11
|
+
)
|
|
17
12
|
|
|
18
13
|
|
|
19
14
|
def main() -> None:
|
|
@@ -24,29 +19,25 @@ def main() -> None:
|
|
|
24
19
|
args = parser.parse_args()
|
|
25
20
|
|
|
26
21
|
lifecycle = load_lifecycle()
|
|
27
|
-
|
|
22
|
+
contract_data = load_phase_contract_data()
|
|
23
|
+
phases = contract_data["phases"]
|
|
28
24
|
target = args.to
|
|
29
25
|
current = lifecycle.get("current_phase")
|
|
30
26
|
require(target in phases, f"Unknown target phase: {target}")
|
|
31
27
|
require(current in phases, f"Current phase is not declared in phase_contracts.yaml: {current}")
|
|
32
28
|
|
|
33
|
-
legal = set(lifecycle.get("allowed_next_phases") or [])
|
|
34
|
-
legal.update(phase_targets(phases[current]))
|
|
35
|
-
if target == "RFC_RECALIBRATION" and current in RFC_INTERRUPT_SOURCES:
|
|
36
|
-
legal.add(target)
|
|
37
|
-
if target == "BLOCKED":
|
|
38
|
-
legal.add(target)
|
|
39
29
|
suspended = lifecycle.get("suspended_phase")
|
|
40
|
-
|
|
41
|
-
|
|
30
|
+
legal = set(phase_transition_targets(contract_data, str(current), str(suspended or "")))
|
|
31
|
+
transition = find_phase_transition(contract_data, str(current), target, str(suspended or ""))
|
|
42
32
|
|
|
43
33
|
require(args.force or target in legal, f"Illegal transition {current} -> {target}. Legal: {sorted(legal)}")
|
|
44
34
|
|
|
45
|
-
|
|
35
|
+
effects = transition.get("effects") if transition else {}
|
|
36
|
+
if not isinstance(effects, dict):
|
|
37
|
+
effects = {}
|
|
38
|
+
if effects.get("set_suspended_phase"):
|
|
46
39
|
lifecycle["suspended_phase"] = current
|
|
47
|
-
|
|
48
|
-
lifecycle["suspended_phase"] = ""
|
|
49
|
-
elif suspended and target == suspended:
|
|
40
|
+
if effects.get("clear_suspended_phase"):
|
|
50
41
|
lifecycle["suspended_phase"] = ""
|
|
51
42
|
|
|
52
43
|
phase = phases[target]
|
|
@@ -54,9 +45,11 @@ def main() -> None:
|
|
|
54
45
|
lifecycle["active_role"] = phase.get("role", "")
|
|
55
46
|
lifecycle["active_skill"] = phase.get("skill", "")
|
|
56
47
|
|
|
57
|
-
lifecycle["allowed_next_phases"] =
|
|
58
|
-
|
|
59
|
-
|
|
48
|
+
lifecycle["allowed_next_phases"] = phase_transition_targets(
|
|
49
|
+
contract_data,
|
|
50
|
+
target,
|
|
51
|
+
str(lifecycle.get("suspended_phase") or ""),
|
|
52
|
+
)
|
|
60
53
|
|
|
61
54
|
dump_yaml(lifecycle, ".codex/state/lifecycle.yaml")
|
|
62
55
|
print(f"Transitioned {current} -> {target}")
|
|
@@ -129,6 +129,11 @@ def validate_self_test_contract_tech_plan_binding(task: dict, normalized_tech_re
|
|
|
129
129
|
contains_any(section, ["module key test path", "模块关键测试路径"]),
|
|
130
130
|
f"Draft task {task_id} tech plan Development Self-Test Contract must include Module key test path: {source}",
|
|
131
131
|
)
|
|
132
|
+
if contract.get("graph_required") is True:
|
|
133
|
+
require(
|
|
134
|
+
contains_any(section, ["module key test graph", "module_key_test_graph", "模块关键测试图"]),
|
|
135
|
+
f"Draft task {task_id} tech plan Development Self-Test Contract must include Module Key Test Graph when graph_required is true: {source}",
|
|
136
|
+
)
|
|
132
137
|
for scenario in contract.get("scenarios") or []:
|
|
133
138
|
if not isinstance(scenario, dict):
|
|
134
139
|
continue
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
from harness_utils import
|
|
2
|
+
from harness_utils import (
|
|
3
|
+
load_lifecycle,
|
|
4
|
+
load_phase_contract_data,
|
|
5
|
+
load_phase_contracts,
|
|
6
|
+
load_yaml,
|
|
7
|
+
phase_transition_contract_errors,
|
|
8
|
+
repo_path,
|
|
9
|
+
require,
|
|
10
|
+
require_paths,
|
|
11
|
+
run_main,
|
|
12
|
+
)
|
|
3
13
|
|
|
4
14
|
|
|
5
15
|
def main() -> None:
|
|
@@ -37,6 +47,7 @@ def main() -> None:
|
|
|
37
47
|
require_paths(required_files + required_dirs)
|
|
38
48
|
|
|
39
49
|
lifecycle = load_lifecycle()
|
|
50
|
+
phase_contract_data = load_phase_contract_data()
|
|
40
51
|
phases = load_phase_contracts()
|
|
41
52
|
load_yaml(".codex/pjsdlc_managed/policies/gates.yaml")
|
|
42
53
|
load_yaml(".codex/pjsdlc_managed/policies/allowed_paths.yaml")
|
|
@@ -44,6 +55,8 @@ def main() -> None:
|
|
|
44
55
|
|
|
45
56
|
current_phase = lifecycle.get("current_phase")
|
|
46
57
|
require(current_phase in phases, f"Lifecycle current_phase is not declared: {current_phase}")
|
|
58
|
+
for error in phase_transition_contract_errors(phase_contract_data, require_transitions=True):
|
|
59
|
+
require(False, error)
|
|
47
60
|
|
|
48
61
|
for phase_name, contract in phases.items():
|
|
49
62
|
skill = contract.get("skill")
|
package/dist/lib/init.js
CHANGED
|
@@ -53,7 +53,7 @@ async function createProjectState(projectRoot, root, report) {
|
|
|
53
53
|
const files = [
|
|
54
54
|
[
|
|
55
55
|
harnessPath(root, "state", "lifecycle.yaml"),
|
|
56
|
-
`project_name: "Project"\nversion: "v0.1"\ncurrent_phase: "SPRINTING"\nactive_role: "developer"\nactive_skill: "pjsdlc_dev_sprint"\ncurrent_milestone: "MVP"\nblocked_reason: ""\nsuspended_phase: ""\nallowed_next_phases:\n - "REVIEWING"\n`
|
|
56
|
+
`project_name: "Project"\nversion: "v0.1"\ncurrent_phase: "SPRINTING"\nactive_role: "developer"\nactive_skill: "pjsdlc_dev_sprint"\ncurrent_milestone: "MVP"\nblocked_reason: ""\nsuspended_phase: ""\nallowed_next_phases:\n - "REVIEWING"\n - "RFC_RECALIBRATION"\n - "BLOCKED"\n`
|
|
57
57
|
],
|
|
58
58
|
[harnessPath(root, "state", "plan.yaml"), `current_task_id: ""\nnext_task_sequence: 1\ntasks: []\n`],
|
|
59
59
|
[harnessPath(root, "state", "plan.draft.yaml"), `next_task_sequence: 1\ntasks: []\n`],
|