monoco-toolkit 0.3.6__py3-none-any.whl → 0.3.10__py3-none-any.whl
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.
- monoco/cli/workspace.py +1 -1
- monoco/core/config.py +58 -0
- monoco/core/hooks/__init__.py +19 -0
- monoco/core/hooks/base.py +104 -0
- monoco/core/hooks/builtin/__init__.py +11 -0
- monoco/core/hooks/builtin/git_cleanup.py +266 -0
- monoco/core/hooks/builtin/logging_hook.py +78 -0
- monoco/core/hooks/context.py +131 -0
- monoco/core/hooks/registry.py +222 -0
- monoco/core/injection.py +63 -29
- monoco/core/integrations.py +8 -2
- monoco/core/output.py +5 -5
- monoco/core/registry.py +9 -1
- monoco/core/resource/__init__.py +5 -0
- monoco/core/resource/finder.py +98 -0
- monoco/core/resource/manager.py +91 -0
- monoco/core/resource/models.py +35 -0
- monoco/core/resources/en/{SKILL.md → skills/monoco_core/SKILL.md} +2 -0
- monoco/core/resources/zh/{SKILL.md → skills/monoco_core/SKILL.md} +2 -0
- monoco/core/setup.py +1 -1
- monoco/core/skill_framework.py +292 -0
- monoco/core/skills.py +538 -254
- monoco/core/sync.py +73 -1
- monoco/core/workflow_converter.py +420 -0
- monoco/features/{scheduler → agent}/__init__.py +5 -3
- monoco/features/agent/adapter.py +31 -0
- monoco/features/agent/apoptosis.py +44 -0
- monoco/features/agent/cli.py +296 -0
- monoco/features/agent/config.py +96 -0
- monoco/features/agent/defaults.py +12 -0
- monoco/features/{scheduler → agent}/engines.py +32 -6
- monoco/features/agent/flow_skills.py +281 -0
- monoco/features/agent/manager.py +91 -0
- monoco/features/{scheduler → agent}/models.py +6 -3
- monoco/features/agent/resources/atoms/atom-code-dev.yaml +61 -0
- monoco/features/agent/resources/atoms/atom-issue-lifecycle.yaml +73 -0
- monoco/features/agent/resources/atoms/atom-knowledge.yaml +55 -0
- monoco/features/agent/resources/atoms/atom-review.yaml +60 -0
- monoco/features/agent/resources/en/skills/flow_engineer/SKILL.md +94 -0
- monoco/features/agent/resources/en/skills/flow_manager/SKILL.md +93 -0
- monoco/features/agent/resources/en/skills/flow_planner/SKILL.md +85 -0
- monoco/features/agent/resources/en/skills/flow_reviewer/SKILL.md +114 -0
- monoco/features/agent/resources/roles/role-engineer.yaml +49 -0
- monoco/features/agent/resources/roles/role-manager.yaml +46 -0
- monoco/features/agent/resources/roles/role-planner.yaml +46 -0
- monoco/features/agent/resources/roles/role-reviewer.yaml +47 -0
- monoco/features/agent/resources/workflows/workflow-dev.yaml +83 -0
- monoco/features/agent/resources/workflows/workflow-issue-create.yaml +72 -0
- monoco/features/agent/resources/workflows/workflow-review.yaml +94 -0
- monoco/features/agent/resources/zh/skills/flow_engineer/SKILL.md +94 -0
- monoco/features/agent/resources/zh/skills/flow_manager/SKILL.md +88 -0
- monoco/features/agent/resources/zh/skills/flow_planner/SKILL.md +259 -0
- monoco/features/agent/resources/zh/skills/flow_reviewer/SKILL.md +137 -0
- monoco/features/{scheduler → agent}/session.py +36 -1
- monoco/features/{scheduler → agent}/worker.py +40 -4
- monoco/features/glossary/adapter.py +31 -0
- monoco/features/glossary/config.py +5 -0
- monoco/features/glossary/resources/en/AGENTS.md +29 -0
- monoco/features/glossary/resources/en/skills/monoco_glossary/SKILL.md +35 -0
- monoco/features/glossary/resources/zh/AGENTS.md +29 -0
- monoco/features/glossary/resources/zh/skills/monoco_glossary/SKILL.md +35 -0
- monoco/features/i18n/resources/en/skills/i18n_scan_workflow/SKILL.md +105 -0
- monoco/features/i18n/resources/en/{SKILL.md → skills/monoco_i18n/SKILL.md} +2 -0
- monoco/features/i18n/resources/zh/skills/i18n_scan_workflow/SKILL.md +105 -0
- monoco/features/i18n/resources/zh/{SKILL.md → skills/monoco_i18n/SKILL.md} +2 -0
- monoco/features/issue/commands.py +427 -21
- monoco/features/issue/core.py +140 -1
- monoco/features/issue/criticality.py +553 -0
- monoco/features/issue/domain/models.py +28 -2
- monoco/features/issue/engine/machine.py +75 -15
- monoco/features/issue/git_service.py +185 -0
- monoco/features/issue/linter.py +291 -62
- monoco/features/issue/models.py +50 -2
- monoco/features/issue/resources/en/skills/issue_create_workflow/SKILL.md +167 -0
- monoco/features/issue/resources/en/skills/issue_develop_workflow/SKILL.md +224 -0
- monoco/features/issue/resources/en/skills/issue_lifecycle_workflow/SKILL.md +159 -0
- monoco/features/issue/resources/en/skills/issue_refine_workflow/SKILL.md +203 -0
- monoco/features/issue/resources/en/{SKILL.md → skills/monoco_issue/SKILL.md} +50 -0
- monoco/features/issue/resources/zh/skills/issue_create_workflow/SKILL.md +167 -0
- monoco/features/issue/resources/zh/skills/issue_develop_workflow/SKILL.md +224 -0
- monoco/features/issue/resources/zh/skills/issue_lifecycle_workflow/SKILL.md +159 -0
- monoco/features/issue/resources/zh/skills/issue_refine_workflow/SKILL.md +203 -0
- monoco/features/issue/resources/zh/{SKILL.md → skills/monoco_issue/SKILL.md} +52 -0
- monoco/features/issue/validator.py +185 -65
- monoco/features/memo/__init__.py +2 -1
- monoco/features/memo/adapter.py +32 -0
- monoco/features/memo/cli.py +36 -14
- monoco/features/memo/core.py +59 -0
- monoco/features/memo/resources/en/skills/monoco_memo/SKILL.md +77 -0
- monoco/features/memo/resources/en/skills/note_processing_workflow/SKILL.md +140 -0
- monoco/features/memo/resources/zh/AGENTS.md +8 -0
- monoco/features/memo/resources/zh/skills/monoco_memo/SKILL.md +77 -0
- monoco/features/memo/resources/zh/skills/note_processing_workflow/SKILL.md +140 -0
- monoco/features/spike/resources/en/{SKILL.md → skills/monoco_spike/SKILL.md} +2 -0
- monoco/features/spike/resources/en/skills/research_workflow/SKILL.md +121 -0
- monoco/features/spike/resources/zh/{SKILL.md → skills/monoco_spike/SKILL.md} +2 -0
- monoco/features/spike/resources/zh/skills/research_workflow/SKILL.md +121 -0
- monoco/main.py +2 -3
- monoco_toolkit-0.3.10.dist-info/METADATA +124 -0
- monoco_toolkit-0.3.10.dist-info/RECORD +156 -0
- monoco/features/scheduler/cli.py +0 -285
- monoco/features/scheduler/config.py +0 -68
- monoco/features/scheduler/defaults.py +0 -54
- monoco/features/scheduler/manager.py +0 -49
- monoco/features/scheduler/reliability.py +0 -106
- monoco/features/skills/core.py +0 -102
- monoco_toolkit-0.3.6.dist-info/METADATA +0 -127
- monoco_toolkit-0.3.6.dist-info/RECORD +0 -97
- /monoco/core/{hooks.py → githooks.py} +0 -0
- /monoco/features/{skills → glossary}/__init__.py +0 -0
- {monoco_toolkit-0.3.6.dist-info → monoco_toolkit-0.3.10.dist-info}/WHEEL +0 -0
- {monoco_toolkit-0.3.6.dist-info → monoco_toolkit-0.3.10.dist-info}/entry_points.txt +0 -0
- {monoco_toolkit-0.3.6.dist-info → monoco_toolkit-0.3.10.dist-info}/licenses/LICENSE +0 -0
monoco/features/issue/core.py
CHANGED
|
@@ -15,12 +15,18 @@ from .models import (
|
|
|
15
15
|
current_time,
|
|
16
16
|
generate_uid,
|
|
17
17
|
)
|
|
18
|
+
from .criticality import (
|
|
19
|
+
CriticalityLevel,
|
|
20
|
+
CriticalityTypeMapping,
|
|
21
|
+
CriticalityInheritanceService,
|
|
22
|
+
)
|
|
18
23
|
from monoco.core import git
|
|
19
24
|
from monoco.core.config import get_config, MonocoConfig
|
|
20
25
|
from monoco.core.lsp import DiagnosticSeverity
|
|
21
26
|
from .validator import IssueValidator
|
|
22
27
|
|
|
23
28
|
from .engine import get_engine
|
|
29
|
+
from .git_service import IssueGitService
|
|
24
30
|
|
|
25
31
|
|
|
26
32
|
def get_prefix_map(issues_root: Path) -> Dict[str, str]:
|
|
@@ -137,6 +143,10 @@ def _serialize_metadata(metadata: IssueMetadata) -> str:
|
|
|
137
143
|
elif k == "parent":
|
|
138
144
|
ordered_data[k] = None
|
|
139
145
|
|
|
146
|
+
# Add criticality if present
|
|
147
|
+
if "criticality" in data:
|
|
148
|
+
ordered_data["criticality"] = data["criticality"]
|
|
149
|
+
|
|
140
150
|
# Add remaining
|
|
141
151
|
for k, v in data.items():
|
|
142
152
|
if k not in ordered_data:
|
|
@@ -211,6 +221,7 @@ def create_issue_file(
|
|
|
211
221
|
subdir: Optional[str] = None,
|
|
212
222
|
sprint: Optional[str] = None,
|
|
213
223
|
tags: List[str] = [],
|
|
224
|
+
criticality: Optional[CriticalityLevel] = None,
|
|
214
225
|
) -> Tuple[IssueMetadata, Path]:
|
|
215
226
|
# Validation
|
|
216
227
|
for dep_id in dependencies:
|
|
@@ -225,6 +236,38 @@ def create_issue_file(
|
|
|
225
236
|
if issue_type != IssueType.EPIC and not parent:
|
|
226
237
|
parent = "EPIC-0000"
|
|
227
238
|
|
|
239
|
+
# Determine criticality
|
|
240
|
+
# 1. Use provided criticality if specified
|
|
241
|
+
# 2. Check parent for inheritance
|
|
242
|
+
# 3. Apply type-based default
|
|
243
|
+
effective_criticality = criticality
|
|
244
|
+
|
|
245
|
+
# Get issue type string for mapping lookup
|
|
246
|
+
issue_type_str = (
|
|
247
|
+
issue_type.value if isinstance(issue_type, IssueType) else str(issue_type)
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
if effective_criticality is None:
|
|
251
|
+
# Check parent inheritance
|
|
252
|
+
if parent:
|
|
253
|
+
parent_path = find_issue_path(issues_root, parent)
|
|
254
|
+
if parent_path:
|
|
255
|
+
parent_meta = parse_issue(parent_path)
|
|
256
|
+
if parent_meta and parent_meta.criticality:
|
|
257
|
+
# Child must inherit at least parent's criticality
|
|
258
|
+
default_type_criticality = CriticalityTypeMapping.get_default(
|
|
259
|
+
issue_type_str
|
|
260
|
+
)
|
|
261
|
+
effective_criticality = (
|
|
262
|
+
CriticalityInheritanceService.resolve_child_criticality(
|
|
263
|
+
parent_meta.criticality, default_type_criticality
|
|
264
|
+
)
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
# Fall back to type-based default
|
|
268
|
+
if effective_criticality is None:
|
|
269
|
+
effective_criticality = CriticalityTypeMapping.get_default(issue_type_str)
|
|
270
|
+
|
|
228
271
|
issue_id = find_next_id(issue_type, issues_root)
|
|
229
272
|
base_type_dir = get_issue_dir(issue_type, issues_root)
|
|
230
273
|
target_dir = base_type_dir / status
|
|
@@ -268,6 +311,7 @@ def create_issue_file(
|
|
|
268
311
|
sprint=sprint,
|
|
269
312
|
tags=final_tags,
|
|
270
313
|
opened_at=current_time() if status == IssueStatus.OPEN else None,
|
|
314
|
+
criticality=effective_criticality,
|
|
271
315
|
)
|
|
272
316
|
|
|
273
317
|
# Enforce lifecycle policies
|
|
@@ -403,6 +447,9 @@ def update_issue(
|
|
|
403
447
|
related: Optional[List[str]] = None,
|
|
404
448
|
tags: Optional[List[str]] = None,
|
|
405
449
|
files: Optional[List[str]] = None,
|
|
450
|
+
criticality: Optional[CriticalityLevel] = None,
|
|
451
|
+
no_commit: bool = False,
|
|
452
|
+
project_root: Optional[Path] = None,
|
|
406
453
|
) -> IssueMetadata:
|
|
407
454
|
path = find_issue_path(issues_root, issue_id)
|
|
408
455
|
if not path:
|
|
@@ -464,13 +511,17 @@ def update_issue(
|
|
|
464
511
|
except ValueError:
|
|
465
512
|
pass
|
|
466
513
|
|
|
514
|
+
# Reconstruct temporary metadata for policy validation
|
|
515
|
+
temp_meta = IssueMetadata(**data)
|
|
516
|
+
|
|
467
517
|
# Use engine to validate the transition
|
|
468
|
-
engine.validate_transition(
|
|
518
|
+
transition = engine.validate_transition(
|
|
469
519
|
from_status=current_status,
|
|
470
520
|
from_stage=current_stage,
|
|
471
521
|
to_status=target_status,
|
|
472
522
|
to_stage=target_stage,
|
|
473
523
|
solution=effective_solution,
|
|
524
|
+
meta=temp_meta,
|
|
474
525
|
)
|
|
475
526
|
|
|
476
527
|
if target_status == "closed":
|
|
@@ -536,6 +587,23 @@ def update_issue(
|
|
|
536
587
|
if files is not None:
|
|
537
588
|
data["files"] = files
|
|
538
589
|
|
|
590
|
+
# Criticality update (only through escalation workflow)
|
|
591
|
+
if criticality is not None:
|
|
592
|
+
current_criticality = data.get("criticality")
|
|
593
|
+
if current_criticality:
|
|
594
|
+
current_level = CriticalityLevel(current_criticality)
|
|
595
|
+
# Only allow escalation (increase), never lowering
|
|
596
|
+
if criticality > current_level:
|
|
597
|
+
data["criticality"] = criticality.value
|
|
598
|
+
elif criticality < current_level:
|
|
599
|
+
raise ValueError(
|
|
600
|
+
f"Cannot lower criticality from {current_level.value} to {criticality.value}. "
|
|
601
|
+
"Criticality is immutable and can only be increased through escalation workflow."
|
|
602
|
+
)
|
|
603
|
+
else:
|
|
604
|
+
# Set if not previously set
|
|
605
|
+
data["criticality"] = criticality.value
|
|
606
|
+
|
|
539
607
|
# Lifecycle Hooks
|
|
540
608
|
# 1. Opened At: If transitioning to OPEN
|
|
541
609
|
if target_status == IssueStatus.OPEN and current_status != IssueStatus.OPEN:
|
|
@@ -591,6 +659,8 @@ def update_issue(
|
|
|
591
659
|
path.write_text(new_content)
|
|
592
660
|
|
|
593
661
|
# 3. Handle physical move if status changed
|
|
662
|
+
# Save old path before move for git tracking
|
|
663
|
+
old_path_before_move = path
|
|
594
664
|
if status and status != current_status:
|
|
595
665
|
# Move file
|
|
596
666
|
prefix = issue_id.split("-")[0].upper()
|
|
@@ -618,12 +688,81 @@ def update_issue(
|
|
|
618
688
|
if updated_meta.parent:
|
|
619
689
|
recalculate_parent(issues_root, updated_meta.parent)
|
|
620
690
|
|
|
691
|
+
# Auto-commit issue file changes (FEAT-0115)
|
|
692
|
+
if not no_commit:
|
|
693
|
+
# Determine the action type for commit message
|
|
694
|
+
action = "update"
|
|
695
|
+
if status and status != current_status:
|
|
696
|
+
action = status # "open", "closed", "backlog"
|
|
697
|
+
elif stage and stage != current_stage:
|
|
698
|
+
action = stage # "draft", "doing", "review", "done"
|
|
699
|
+
|
|
700
|
+
# Resolve project root if not provided
|
|
701
|
+
if project_root is None:
|
|
702
|
+
project_root = issues_root.parent
|
|
703
|
+
|
|
704
|
+
# Only auto-commit if we're in a git repo
|
|
705
|
+
git_service = IssueGitService(project_root)
|
|
706
|
+
if git_service.is_git_repository():
|
|
707
|
+
# Use the saved old path before file move for git tracking
|
|
708
|
+
old_path_for_git = None
|
|
709
|
+
if status and status != current_status and old_path_before_move != path:
|
|
710
|
+
old_path_for_git = old_path_before_move
|
|
711
|
+
|
|
712
|
+
commit_result = git_service.commit_issue_change(
|
|
713
|
+
issue_id=issue_id,
|
|
714
|
+
action=action,
|
|
715
|
+
issue_file_path=path,
|
|
716
|
+
old_file_path=old_path_for_git,
|
|
717
|
+
no_commit=no_commit,
|
|
718
|
+
)
|
|
719
|
+
# Attach commit result to metadata for optional inspection
|
|
720
|
+
updated_meta.commit_result = commit_result
|
|
721
|
+
|
|
621
722
|
# Update returned metadata with final absolute path
|
|
622
723
|
updated_meta.path = str(path.absolute())
|
|
623
724
|
updated_meta.actions = get_available_actions(updated_meta)
|
|
725
|
+
|
|
726
|
+
# Execute Post Actions (Trigger)
|
|
727
|
+
if transition and hasattr(transition, "post_actions") and transition.post_actions:
|
|
728
|
+
_execute_post_actions(transition.post_actions, updated_meta)
|
|
729
|
+
|
|
624
730
|
return updated_meta
|
|
625
731
|
|
|
626
732
|
|
|
733
|
+
def _execute_post_actions(actions: List[str], meta: IssueMetadata):
|
|
734
|
+
"""
|
|
735
|
+
Execute a list of shell commands as post-actions.
|
|
736
|
+
Supports template substitution with issue metadata.
|
|
737
|
+
"""
|
|
738
|
+
import shlex
|
|
739
|
+
import subprocess
|
|
740
|
+
from rich.console import Console
|
|
741
|
+
|
|
742
|
+
console = Console()
|
|
743
|
+
data = meta.model_dump(mode="json")
|
|
744
|
+
|
|
745
|
+
for action in actions:
|
|
746
|
+
try:
|
|
747
|
+
# Safe template substitution
|
|
748
|
+
cmd = action.format(**data)
|
|
749
|
+
except KeyError as e:
|
|
750
|
+
console.print(f"[yellow]Trigger Warning:[/yellow] Missing key for template '{action}': {e}")
|
|
751
|
+
continue
|
|
752
|
+
|
|
753
|
+
console.print(f"[bold cyan]Triggering:[/bold cyan] {cmd}")
|
|
754
|
+
|
|
755
|
+
args = shlex.split(cmd)
|
|
756
|
+
|
|
757
|
+
try:
|
|
758
|
+
# Run in foreground to allow interaction if needed (e.g. agent output)
|
|
759
|
+
subprocess.run(args, check=True)
|
|
760
|
+
except subprocess.CalledProcessError as e:
|
|
761
|
+
console.print(f"[red]Trigger Failed:[/red] Command '{cmd}' exited with code {e.returncode}")
|
|
762
|
+
except Exception as e:
|
|
763
|
+
console.print(f"[red]Trigger Error:[/red] {e}")
|
|
764
|
+
|
|
765
|
+
|
|
627
766
|
def start_issue_isolation(
|
|
628
767
|
issues_root: Path, issue_id: str, mode: str, project_root: Path
|
|
629
768
|
) -> IssueMetadata:
|