pactkit 1.0.0__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.
pactkit/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ """PactKit - Spec-driven agentic DevOps toolkit."""
2
+
3
+ __version__ = "1.0.0"
pactkit/cli.py ADDED
@@ -0,0 +1,78 @@
1
+ """PactKit CLI — Spec-driven agentic DevOps toolkit.
2
+
3
+ Usage:
4
+ pactkit init # Deploy Expert mode (default)
5
+ pactkit init --mode common # Deploy lightweight Common mode
6
+ pactkit init -t /tmp/preview # Preview to custom directory
7
+ pactkit update # Re-deploy (same as init, idempotent)
8
+ pactkit version # Show version
9
+ """
10
+ import argparse
11
+ import sys
12
+
13
+ from pactkit import __version__
14
+
15
+
16
+ def main():
17
+ parser = argparse.ArgumentParser(
18
+ prog="pactkit",
19
+ description="PactKit — Spec-driven agentic DevOps toolkit",
20
+ )
21
+ subparsers = parser.add_subparsers(dest="command")
22
+
23
+ # pactkit init
24
+ init_parser = subparsers.add_parser("init", help="Deploy PactKit configuration")
25
+ init_parser.add_argument(
26
+ "--mode",
27
+ choices=["expert", "common"],
28
+ default="expert",
29
+ help="Deployment mode: expert (full, default) or common (lightweight)",
30
+ )
31
+ init_parser.add_argument(
32
+ "-t", "--target",
33
+ type=str,
34
+ default=None,
35
+ help="Custom target directory (default: ~/.claude)",
36
+ )
37
+
38
+ # pactkit update (alias for init)
39
+ update_parser = subparsers.add_parser("update", help="Re-deploy PactKit configuration")
40
+ update_parser.add_argument(
41
+ "--mode",
42
+ choices=["expert", "common"],
43
+ default="expert",
44
+ help="Deployment mode: expert (full, default) or common (lightweight)",
45
+ )
46
+ update_parser.add_argument(
47
+ "-t", "--target",
48
+ type=str,
49
+ default=None,
50
+ help="Custom target directory (default: ~/.claude)",
51
+ )
52
+
53
+ # pactkit version
54
+ subparsers.add_parser("version", help="Show PactKit version")
55
+
56
+ args = parser.parse_args()
57
+
58
+ if args.command in ("init", "update"):
59
+ if args.mode == "expert":
60
+ from pactkit.generators.deployer import deploy
61
+ deploy()
62
+ else:
63
+ from pactkit.common_user import main as common_main
64
+ # Simulate CLI args for common_user
65
+ sys.argv = ["pactkit"]
66
+ if args.target:
67
+ sys.argv.extend(["-t", args.target])
68
+ common_main()
69
+
70
+ elif args.command == "version":
71
+ print(f"PactKit v{__version__}")
72
+
73
+ else:
74
+ parser.print_help()
75
+
76
+
77
+ if __name__ == "__main__":
78
+ main()
pactkit/common_user.py ADDED
@@ -0,0 +1,219 @@
1
+ """
2
+ PactKit Common User Installer (Experience Mode)
3
+ Standalone, self-contained, zero external dependencies.
4
+ Generates a lightweight PDCA workflow for Claude Code.
5
+
6
+ Usage:
7
+ pactkit init --mode common # Install to ~/.claude/
8
+ pactkit init --mode common -t /tmp/out # Preview to custom dir
9
+ """
10
+ import argparse
11
+ import textwrap
12
+ from pathlib import Path
13
+
14
+
15
+ # --- Configuration ---
16
+ class Colors:
17
+ GREEN = '\033[92m'
18
+ BLUE = '\033[94m'
19
+ YELLOW = '\033[93m'
20
+ ENDC = '\033[0m'
21
+
22
+ def print_success(msg): print(f"{Colors.GREEN}[SUCCESS]{Colors.ENDC} {msg}")
23
+ def print_info(msg): print(f"{Colors.BLUE}[INFO]{Colors.ENDC} {msg}")
24
+ def print_warn(msg): print(f"{Colors.YELLOW}[WARN]{Colors.ENDC} {msg}")
25
+
26
+ def ensure_file(path: Path, content: str):
27
+ path.parent.mkdir(parents=True, exist_ok=True)
28
+ path.write_text(content.strip(), encoding="utf-8")
29
+ print_success(f"Generated: {path}")
30
+
31
+ # --- Content Definitions ---
32
+
33
+ def get_common_user_config():
34
+ """
35
+ Experience Mode Configuration.
36
+ Pure prompt injection only. No scripts, no tools, no cross-file references.
37
+ """
38
+
39
+ claude_md = textwrap.dedent("""\
40
+ # Claude Code — Lightweight PDCA
41
+
42
+ ## Core Protocol
43
+ - **Language**: Mirror the user's input language.
44
+ - **Tone**: Concise, professional, engineering-first.
45
+ - **Git**: Use Conventional Commits (`feat`, `fix`, `docs`, `chore`).
46
+
47
+ ## Workflow: PDCA
48
+ This environment follows a lightweight **Plan → Act → Check → Done** cycle:
49
+
50
+ | Step | Command | What it does |
51
+ |------|---------|--------------|
52
+ | Plan | `/plan` | Analyze the request, create a TODO list |
53
+ | Act | `/act` | Implement the next pending task |
54
+ | Check| `/check`| Review code quality and run tests |
55
+ | Done | `/done` | Summarize work and prepare a git commit |
56
+
57
+ ## Guidelines
58
+ - Keep plans in a `TODO.md` file at the project root.
59
+ - One task at a time: implement, then review, then commit.
60
+ - Prefer editing existing files over creating new ones.
61
+ """)
62
+
63
+ cmd_plan = textwrap.dedent("""\
64
+ ---
65
+ description: "Analyze requirements and create a plan"
66
+ ---
67
+
68
+ # Command: Plan (Lite)
69
+ - **Usage**: `/plan "Feature or bug description"`
70
+
71
+ ## Your Role
72
+ You are a Technical Lead. Analyze the user's request and create a structured plan.
73
+
74
+ ## Steps
75
+ 1. Read the user's request carefully.
76
+ 2. If a `TODO.md` exists at the project root, read it and update it.
77
+ If not, create a new `TODO.md`.
78
+ 3. Break down the requirement into clear, checkable steps:
79
+ - Use `- [ ] Step description` format.
80
+ - Each step should be small enough to implement in one pass.
81
+ 4. Identify which existing files will need changes.
82
+
83
+ ## Rules
84
+ - Do NOT write any code in this step — only plan.
85
+ - Do NOT create new directories or files (except `TODO.md`).
86
+ - Present the plan to the user for confirmation before proceeding.
87
+ """)
88
+
89
+ cmd_act = textwrap.dedent("""\
90
+ ---
91
+ description: "Implement the next task from the plan"
92
+ ---
93
+
94
+ # Command: Act (Lite)
95
+ - **Usage**: `/act`
96
+
97
+ ## Your Role
98
+ You are a Developer. Execute the next pending task from the plan.
99
+
100
+ ## Steps
101
+ 1. Read `TODO.md` to find the first unchecked item (`- [ ]`).
102
+ 2. Understand the relevant code context by reading the target files.
103
+ 3. Write the code to implement this single task.
104
+ 4. Mark the item as done: `- [x]` in `TODO.md`.
105
+
106
+ ## Rules
107
+ - Implement only ONE task per invocation.
108
+ - Prefer editing existing files over creating new ones.
109
+ - Stop after implementation — do not review or commit.
110
+ """)
111
+
112
+ cmd_check = textwrap.dedent("""\
113
+ ---
114
+ description: "Review code and run tests"
115
+ ---
116
+
117
+ # Command: Check (Lite)
118
+ - **Usage**: `/check`
119
+
120
+ ## Your Role
121
+ You are a Code Reviewer. Verify the quality of recent changes.
122
+
123
+ ## Steps
124
+ 1. Review the files modified since the last commit (`git diff`).
125
+ 2. Check for:
126
+ - Logic errors or obvious bugs
127
+ - Syntax issues
128
+ - Deviations from the plan in `TODO.md`
129
+ 3. If tests exist in the project, run them.
130
+ 4. Report findings to the user.
131
+
132
+ ## Rules
133
+ - Do NOT fix issues yourself — only report them.
134
+ - If tests fail, explain which tests failed and why.
135
+ - If everything looks good, say so and suggest proceeding to `/done`.
136
+ """)
137
+
138
+ cmd_done = textwrap.dedent("""\
139
+ ---
140
+ description: "Summarize work and prepare a git commit"
141
+ ---
142
+
143
+ # Command: Done (Lite)
144
+ - **Usage**: `/done`
145
+
146
+ ## Your Role
147
+ You are a Release Engineer. Wrap up the current work session.
148
+
149
+ ## Steps
150
+ 1. Read `TODO.md` to summarize what was completed.
151
+ 2. Review `git diff` to confirm all changes are intentional.
152
+ 3. Generate a Conventional Commit message:
153
+ - Format: `type(scope): description`
154
+ - Types: `feat`, `fix`, `docs`, `chore`, `refactor`, `test`
155
+ 4. Present the commit command to the user for confirmation.
156
+ 5. After the user confirms, execute the commit.
157
+ 6. Clean up completed items in `TODO.md` (remove or archive them).
158
+
159
+ ## Rules
160
+ - NEVER commit without user confirmation.
161
+ - NEVER push to remote unless the user explicitly asks.
162
+ """)
163
+
164
+ return {
165
+ "claude_md": claude_md,
166
+ "commands": {
167
+ "plan.md": cmd_plan,
168
+ "act.md": cmd_act,
169
+ "check.md": cmd_check,
170
+ "done.md": cmd_done,
171
+ }
172
+ }
173
+
174
+
175
+ def main():
176
+ parser = argparse.ArgumentParser(description="PactKit Common User Installer (Experience Mode)")
177
+ parser.add_argument("-t", "--target", type=str, help="Specify target directory (default: ~/.claude)", default=None)
178
+ args = parser.parse_args()
179
+
180
+ if args.target:
181
+ claude_root = Path(args.target).resolve()
182
+ print_warn(f"Running in PREVIEW mode. Generating files to: {claude_root}")
183
+ else:
184
+ claude_root = Path.home() / ".claude"
185
+ print_info("Running in INSTALL mode. Targeting: ~/.claude")
186
+
187
+ config = get_common_user_config()
188
+
189
+ # 1. Generate CLAUDE.md (inline PDCA, no cross-file references)
190
+ ensure_file(claude_root / "CLAUDE.md", config["claude_md"])
191
+
192
+ # 2. Generate Commands (4 lightweight PDCA commands)
193
+ cmds_dir = claude_root / "commands"
194
+ for filename, content in config["commands"].items():
195
+ ensure_file(cmds_dir / filename, content)
196
+
197
+ print_info("Common User Configuration Generated!")
198
+
199
+ if args.target:
200
+ print(f"""
201
+ {Colors.YELLOW}Preview Generation Complete.{Colors.ENDC}
202
+ Check the '{args.target}' directory to verify the structure.
203
+
204
+ To install for real, run:
205
+ {Colors.GREEN}pactkit init --mode common{Colors.ENDC}
206
+ """)
207
+ else:
208
+ print(f"""
209
+ {Colors.GREEN}Your Environment is ready! (Experience Mode){Colors.ENDC}
210
+
211
+ How to use (in any project):
212
+ 1. {Colors.BLUE}/plan "Fix login bug"{Colors.ENDC} -> Creates TODO.md
213
+ 2. {Colors.BLUE}/act{Colors.ENDC} -> Writes code
214
+ 3. {Colors.BLUE}/check{Colors.ENDC} -> Reviews code
215
+ 4. {Colors.BLUE}/done{Colors.ENDC} -> Commits code
216
+ """)
217
+
218
+ if __name__ == "__main__":
219
+ main()
File without changes
@@ -0,0 +1,157 @@
1
+ import sys
2
+ from pathlib import Path
3
+
4
+ # 确保能 import pactkit.prompts
5
+ current_dir = Path(__file__).resolve().parent
6
+ project_root = current_dir.parent.parent
7
+ if str(project_root) not in sys.path:
8
+ sys.path.insert(0, str(project_root))
9
+
10
+ from pactkit import prompts
11
+ from pactkit.skills import load_script
12
+ from pactkit.utils import atomic_write
13
+
14
+
15
+ def deploy(mode="expert"):
16
+ print("🚀 PactKit DevOps Deployment (v20.0 - EXPERT Mode)")
17
+
18
+ # 1. 准备目录
19
+ claude_root = Path.home() / ".claude"
20
+ agents_dir = claude_root / "agents"
21
+ commands_dir = claude_root / "commands"
22
+ skills_dir = claude_root / "skills"
23
+
24
+ for d in [claude_root, agents_dir, commands_dir, skills_dir]:
25
+ d.mkdir(parents=True, exist_ok=True)
26
+
27
+ # 2. 部署 Skills (v20.0 Compliant Skill Structure)
28
+ _deploy_skills(skills_dir)
29
+
30
+ # 3. 清理旧文件
31
+ _cleanup_legacy(skills_dir)
32
+
33
+ # 4. 部署 Expert 配置
34
+ _deploy_expert(claude_root, agents_dir, commands_dir)
35
+
36
+ print("\n🎉 Deployment Complete.")
37
+
38
+
39
+ def _deploy_skills(skills_dir):
40
+ """部署合规的 Skill 目录结构"""
41
+ skill_defs = [
42
+ {
43
+ 'name': 'pactkit-visualize',
44
+ 'skill_md': prompts.SKILL_VISUALIZE_MD,
45
+ 'script_name': 'visualize.py',
46
+ 'script_source': load_script('visualize.py'),
47
+ },
48
+ {
49
+ 'name': 'pactkit-board',
50
+ 'skill_md': prompts.SKILL_BOARD_MD,
51
+ 'script_name': 'board.py',
52
+ 'script_source': load_script('board.py'),
53
+ },
54
+ {
55
+ 'name': 'pactkit-scaffold',
56
+ 'skill_md': prompts.SKILL_SCAFFOLD_MD,
57
+ 'script_name': 'scaffold.py',
58
+ 'script_source': load_script('scaffold.py'),
59
+ },
60
+ ]
61
+
62
+ for sd in skill_defs:
63
+ skill_dir = skills_dir / sd['name']
64
+ scripts_dir = skill_dir / 'scripts'
65
+ scripts_dir.mkdir(parents=True, exist_ok=True)
66
+
67
+ atomic_write(skill_dir / 'SKILL.md', sd['skill_md'])
68
+ atomic_write(scripts_dir / sd['script_name'], sd['script_source'])
69
+
70
+ print(f"✅ Deployed {len(skill_defs)} Skills (Compliant Structure)")
71
+
72
+
73
+ def _cleanup_legacy(skills_dir):
74
+ """清理旧的 pactkit_tools.py"""
75
+ legacy = skills_dir / 'pactkit_tools.py'
76
+ if legacy.exists():
77
+ legacy.unlink()
78
+ print(f"🧹 Removed legacy: {legacy}")
79
+
80
+
81
+ def _deploy_rules(claude_root):
82
+ """部署模块化规则到 ~/.claude/rules/,保护用户自定义文件"""
83
+ rules_dir = claude_root / "rules"
84
+ rules_dir.mkdir(parents=True, exist_ok=True)
85
+
86
+ # 清理受管理的文件(01-04 前缀),保留用户文件(10+)
87
+ for f in rules_dir.glob('*.md'):
88
+ if any(f.name.startswith(p) for p in prompts.RULES_MANAGED_PREFIXES):
89
+ f.unlink()
90
+
91
+ # 写入规则模块
92
+ for key, filename in prompts.RULES_FILES.items():
93
+ atomic_write(rules_dir / filename, prompts.RULES_MODULES[key])
94
+
95
+ print(f"✅ Deployed {len(prompts.RULES_FILES)} Rule Modules")
96
+
97
+
98
+ def _cleanup_managed(directory, managed_names, prefix=None):
99
+ """清理受管理文件,保留用户自定义文件。
100
+
101
+ Args:
102
+ directory: 目标目录
103
+ managed_names: 受管理的文件名集合(含扩展名)
104
+ prefix: 如果提供,按前缀匹配清理;否则按 managed_names 精确匹配
105
+ """
106
+ if not directory.exists():
107
+ return
108
+ for f in directory.glob('*.md'):
109
+ if prefix and f.name.startswith(prefix):
110
+ f.unlink()
111
+ elif not prefix and f.name in managed_names:
112
+ f.unlink()
113
+
114
+
115
+ def _deploy_expert(claude_root, agents_dir, commands_dir):
116
+ # 部署模块化规则
117
+ _deploy_rules(claude_root)
118
+
119
+ # 部署精简版 CLAUDE.md(@import 引用)
120
+ atomic_write(claude_root / "CLAUDE.md", prompts.CLAUDE_MD_TEMPLATE)
121
+ print("✅ Constitution Updated (Modular)")
122
+
123
+ # 清理旧的受管理 Agent 文件,保留用户自定义 Agent
124
+ managed_agent_files = {f"{name}.md" for name in prompts.AGENTS_EXPERT}
125
+ _cleanup_managed(agents_dir, managed_agent_files)
126
+
127
+ # 部署 Agents (满血版 + 高级字段)
128
+ OPTIONAL_FIELDS = ['permissionMode', 'disallowedTools', 'maxTurns', 'memory', 'skills']
129
+ for name, cfg in prompts.AGENTS_EXPERT.items():
130
+ agent_path = agents_dir / f"{name}.md"
131
+ content = [
132
+ "---",
133
+ f"name: {name}",
134
+ f"description: {cfg['desc']}",
135
+ f"tools: {cfg['tools']}",
136
+ f"model: {cfg.get('model', 'sonnet')}",
137
+ ]
138
+ for field in OPTIONAL_FIELDS:
139
+ if field in cfg:
140
+ content.append(f"{field}: {cfg[field]}")
141
+ content.extend([
142
+ "---",
143
+ "",
144
+ cfg['prompt'],
145
+ "",
146
+ "Please refer to ~/.claude/CLAUDE.md for routing."
147
+ ])
148
+ atomic_write(agent_path, "\n".join(content))
149
+ print(f"✅ Deployed {len(prompts.AGENTS_EXPERT)} Expert Agents")
150
+
151
+ # 清理旧的受管理 Command 文件,保留用户自定义命令
152
+ _cleanup_managed(commands_dir, set(), prefix="project-")
153
+
154
+ # 部署 Commands (满血版)
155
+ for filename, content in prompts.COMMANDS_CONTENT.items():
156
+ atomic_write(commands_dir / filename, content)
157
+ print(f"✅ Deployed {len(prompts.COMMANDS_CONTENT)} Command Playbooks")
@@ -0,0 +1,45 @@
1
+ from .agents import (
2
+ AGENTS_EXPERT,
3
+ )
4
+ from .commands import COMMANDS_CONTENT
5
+ from .references import (
6
+ DEV_REF_BACKEND,
7
+ DEV_REF_FRONTEND,
8
+ REVIEW_REF_QUALITY,
9
+ REVIEW_REF_REMOVAL,
10
+ REVIEW_REF_SECURITY,
11
+ REVIEW_REF_SOLID,
12
+ TEST_REF_GO,
13
+ TEST_REF_JAVA,
14
+ TEST_REF_NODE,
15
+ TEST_REF_PYTHON,
16
+ )
17
+ from .rules import (
18
+ CLAUDE_MD_TEMPLATE,
19
+ CONSTITUTION_EXPERT,
20
+ RULES_FILES,
21
+ RULES_MANAGED_PREFIXES,
22
+ RULES_MODULES,
23
+ )
24
+ from .skills import (
25
+ BOARD_SOURCE,
26
+ SCAFFOLD_SOURCE,
27
+ SKILL_BOARD_MD,
28
+ SKILL_SCAFFOLD_MD,
29
+ SKILL_VISUALIZE_MD,
30
+ TOOLS_CONTENT,
31
+ TOOLS_SOURCE,
32
+ VISUALIZE_SOURCE,
33
+ )
34
+ from .workflows import (
35
+ DESIGN_PROMPT,
36
+ DRAW_PROMPT_TEMPLATE,
37
+ DRAW_REF_ANTI_BUGS,
38
+ DRAW_REF_LAYOUTS,
39
+ DRAW_REF_STYLES,
40
+ HOTFIX_PROMPT,
41
+ LANG_PROFILES,
42
+ REVIEW_PROMPT,
43
+ SPRINT_PROMPT,
44
+ TRACE_PROMPT,
45
+ )