pactkit-codex 2.10.2__tar.gz → 2.17.0__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pactkit-codex
3
- Version: 2.10.2
3
+ Version: 2.17.0
4
4
  Summary: PactKit adapter for OpenAI Codex CLI
5
5
  Author: Slim
6
6
  License: MIT
@@ -21,7 +21,7 @@ Classifier: Topic :: Software Development :: Quality Assurance
21
21
  Requires-Python: >=3.10
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
- Requires-Dist: pactkit>=2.9.0
24
+ Requires-Dist: pactkit>=2.17.0
25
25
  Requires-Dist: tomli>=1.1.0; python_version < "3.11"
26
26
  Dynamic: license-file
27
27
 
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pactkit-codex"
7
- version = "2.10.2"
7
+ version = "2.17.0"
8
8
  description = "PactKit adapter for OpenAI Codex CLI"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
11
11
  requires-python = ">=3.10"
12
12
  dependencies = [
13
- "pactkit>=2.9.0",
13
+ "pactkit>=2.17.0",
14
14
  "tomli>=1.1.0; python_version < '3.11'",
15
15
  ]
16
16
 
@@ -14,10 +14,6 @@ Codex-specific features:
14
14
  import re
15
15
  from pathlib import Path
16
16
 
17
- try:
18
- import tomllib
19
- except ModuleNotFoundError:
20
- import tomli as tomllib # Python 3.10 fallback
21
17
  from pactkit import __version__, prompts
22
18
  from pactkit.config import (
23
19
  VALID_SKILLS,
@@ -35,7 +31,6 @@ from pactkit.prompts.rules import (
35
31
  CREDENTIAL_SAFETY_FILE,
36
32
  RULES_FILES,
37
33
  )
38
- from pactkit.skills import load_script
39
34
  from pactkit.utils import atomic_write
40
35
 
41
36
  # Commands excluded from Codex deployment (require multi-agent capabilities)
@@ -130,6 +125,11 @@ class CodexDeployer(DeployerBase):
130
125
 
131
126
  self.write_version_marker(codex_root)
132
127
 
128
+ # STORY-slim-139 R2: machine-readable deployment manifest
129
+ from pactkit.deploy_manifest import write_deploy_manifest
130
+
131
+ write_deploy_manifest(codex_root, "codex", cfg)
132
+
133
133
  print(
134
134
  f"\n✅ Codex CLI: {n_skills} Skills, {n_commands} Commands → {codex_root}"
135
135
  )
@@ -168,6 +168,7 @@ class CodexDeployer(DeployerBase):
168
168
  content = content.replace(pattern, "~/.codex/")
169
169
  content = CodexDeployer.strip_model_references(content)
170
170
  content = DeployerBase.strip_excluded_command_references(content, profile)
171
+ content = _replace_cli_with_scripts(content)
171
172
  atomic_write(rules_dir / filename, content + "\n")
172
173
 
173
174
  cred_path = rules_dir / CREDENTIAL_SAFETY_FILE
@@ -286,7 +287,7 @@ class CodexDeployer(DeployerBase):
286
287
  content = _replace_cli_with_scripts(content)
287
288
 
288
289
  # Build SKILL.md with frontmatter + @references + content
289
- rule_keys = COMMAND_RULES_MAP.get(cmd_name, ["core", "credential"])
290
+ rule_keys = COMMAND_RULES_MAP.get(cmd_name, ["pactkit", "credential"])
290
291
  refs = []
291
292
  for key in rule_keys:
292
293
  if key == "credential":
@@ -306,48 +307,32 @@ class CodexDeployer(DeployerBase):
306
307
 
307
308
  @staticmethod
308
309
  def generate_codex_config_toml(codex_root):
309
- """Generate or merge config.toml for Codex CLI.
310
-
311
- R1: Create with PactKit-managed sections if absent.
312
- R4: Merge additive-only for user fields when existing.
313
- R5: Never write API keys or secrets.
314
- R6: Mark managed sections with [pactkit:managed] comments.
310
+ """Create config.toml for Codex CLI — but NEVER modify an existing one.
311
+
312
+ config.toml carries the user's providers, MCP servers, project trust
313
+ and other sensitive state. PactKit's share is two scalar defaults and
314
+ one MCP entry — not worth any write risk. Policy (2026-08-13, user
315
+ directive after two wipe incidents):
316
+ - File exists -> leave it BYTE-IDENTICAL, print the recommended
317
+ settings for the user to add by hand.
318
+ - File missing -> create it with the PactKit-managed sections.
315
319
  """
316
320
  config_path = codex_root / "config.toml"
317
321
 
318
- pactkit_defaults = {
319
- "sandbox_mode": "workspace-write",
320
- "approval_policy": "on-request",
321
- }
322
- pactkit_mcp = {
323
- "context7": {"url": "https://mcp.context7.com/mcp"},
324
- }
325
-
326
- FORBIDDEN_KEYS = {"api_key", "OPENAI_API_KEY", "organization"}
327
-
328
322
  if config_path.exists():
329
- try:
330
- existing = tomllib.loads(config_path.read_text())
331
- except Exception:
332
- # User-edited config may have non-standard TOML; preserve it
333
- existing = {}
334
- for key, value in pactkit_defaults.items():
335
- if key not in existing:
336
- existing[key] = value
337
- if "mcp_servers" not in existing:
338
- existing["mcp_servers"] = {}
339
- for name, cfg in pactkit_mcp.items():
340
- if name not in existing["mcp_servers"]:
341
- existing["mcp_servers"][name] = cfg
342
- merged = existing
343
- else:
344
- merged = dict(pactkit_defaults)
345
- merged["mcp_servers"] = dict(pactkit_mcp)
346
-
347
- for key in FORBIDDEN_KEYS:
348
- merged.pop(key, None)
323
+ print(" ℹ️ config.toml exists — left untouched (PactKit never modifies it)")
324
+ return
349
325
 
350
- _write_toml_with_markers(config_path, merged)
326
+ lines = [
327
+ "# [pactkit:managed]",
328
+ 'sandbox_mode = "workspace-write"',
329
+ 'approval_policy = "on-request"',
330
+ "",
331
+ "# [pactkit:managed]",
332
+ "[mcp_servers.context7]",
333
+ 'url = "https://mcp.context7.com/mcp"',
334
+ ]
335
+ atomic_write(config_path, chr(10).join(lines) + chr(10))
351
336
 
352
337
  @staticmethod
353
338
  def generate_codex_project_files(project_root):
@@ -397,67 +382,32 @@ class CodexDeployer(DeployerBase):
397
382
  """Deploy skills with Codex-specific path replacement in scripts."""
398
383
  _prefix = profile.skills_path_var
399
384
 
400
- scripted_skill_defs = [
401
- {
402
- "name": "pactkit-visualize",
403
- "skill_md": prompts.SKILL_VISUALIZE_MD,
404
- "script_name": "visualize.py",
405
- "script_source": load_script("visualize.py"),
406
- },
407
- {
408
- "name": "pactkit-board",
409
- "skill_md": prompts.SKILL_BOARD_MD,
410
- "script_name": "board.py",
411
- "script_source": load_script("board.py"),
412
- },
413
- {
414
- "name": "pactkit-scaffold",
415
- "skill_md": prompts.SKILL_SCAFFOLD_MD,
416
- "script_name": "scaffold.py",
417
- "script_source": load_script("scaffold.py"),
418
- },
419
- ]
420
-
421
- prompt_only_skill_defs = [
422
- {"name": "pactkit-trace", "skill_md": prompts.SKILL_TRACE_MD},
423
- {"name": "pactkit-draw", "skill_md": prompts.SKILL_DRAW_MD},
424
- {"name": "pactkit-status", "skill_md": prompts.SKILL_STATUS_MD},
425
- {"name": "pactkit-doctor", "skill_md": prompts.SKILL_DOCTOR_MD},
426
- {"name": "pactkit-review", "skill_md": prompts.SKILL_REVIEW_MD},
427
- {"name": "pactkit-release", "skill_md": prompts.SKILL_RELEASE_MD},
428
- {"name": "pactkit-analyze", "skill_md": prompts.SKILL_ANALYZE_MD},
429
- ]
385
+ # STORY-slim-139 R4: consume the core SKILL_MANIFEST — no local
386
+ # hardcoded skill list (the old 10-item snapshot silently dropped
387
+ # garden/audit/report when core added them).
388
+ from pactkit.generators.deployer import _render_skill_md
389
+ from pactkit.prompts.skills import get_skill_manifest
430
390
 
431
391
  enabled_set = set(enabled_skills)
432
392
  deployed = 0
433
393
 
434
- for sd in scripted_skill_defs:
435
- if sd["name"] not in enabled_set:
436
- continue
437
- skill_dir = skills_dir / sd["name"]
438
- scripts_dir = skill_dir / "scripts"
439
- scripts_dir.mkdir(parents=True, exist_ok=True)
440
-
441
- from pactkit.generators.deployer import _render_skill_md
442
- skill_md = _render_skill_md(sd, profile, _prefix)
443
- skill_md = _replace_cli_with_scripts(skill_md)
444
- atomic_write(skill_dir / "SKILL.md", skill_md)
445
- script_content = sd["script_source"]
446
- script_content = script_content.replace("~/.claude/", f"{profile.global_config_dir}/")
447
- script_content = script_content.replace("~/.config/opencode/", f"{profile.global_config_dir}/")
448
- atomic_write(scripts_dir / sd["script_name"], script_content)
449
- deployed += 1
450
-
451
- for sd in prompt_only_skill_defs:
394
+ for sd in get_skill_manifest():
452
395
  if sd["name"] not in enabled_set:
453
396
  continue
454
397
  skill_dir = skills_dir / sd["name"]
455
398
  skill_dir.mkdir(parents=True, exist_ok=True)
456
399
 
457
- from pactkit.generators.deployer import _render_skill_md
458
400
  skill_md = _render_skill_md(sd, profile, _prefix)
459
401
  skill_md = _replace_cli_with_scripts(skill_md)
402
+ skill_md = CodexDeployer.strip_model_references(skill_md)
460
403
  atomic_write(skill_dir / "SKILL.md", skill_md)
404
+ if sd["script_name"]:
405
+ scripts_dir = skill_dir / "scripts"
406
+ scripts_dir.mkdir(exist_ok=True)
407
+ script_content = sd["script_source"]
408
+ script_content = script_content.replace("~/.claude/", f"{profile.global_config_dir}/")
409
+ script_content = script_content.replace("~/.config/opencode/", f"{profile.global_config_dir}/")
410
+ atomic_write(scripts_dir / sd["script_name"], script_content)
461
411
  deployed += 1
462
412
 
463
413
  return deployed
@@ -594,7 +544,9 @@ _SCAFFOLD_SCRIPT = "python3 ~/.codex/skills/pactkit-scaffold/scripts/scaffold.py
594
544
  _CLI_TO_SCRIPT = [
595
545
  # visualize variants (order matters: longer patterns first)
596
546
  ("Run `pactkit visualize --lazy`", f"Run `{_VIZ_SCRIPT}` (file, `--mode class`, `--mode call` if source changed)"),
547
+ ("`pactkit visualize --lazy`", f"`{_VIZ_SCRIPT}` (file, `--mode class`, `--mode call` if source changed)"),
597
548
  ("Run `pactkit visualize", f"Run `{_VIZ_SCRIPT}"),
549
+ ("`pactkit visualize", f"`{_VIZ_SCRIPT}"),
598
550
  ("Run `visualize --focus", f"Run `{_VIZ_SCRIPT} --focus"),
599
551
  ("Run `visualize --mode", f"Run `{_VIZ_SCRIPT} --mode"),
600
552
  ("Run `visualize`", f"Run `{_VIZ_SCRIPT}`"),
@@ -602,8 +554,14 @@ _CLI_TO_SCRIPT = [
602
554
  ("Run `python3 ~/.codex/skills/pactkit-board/scripts/board.py", f"Run `{_BOARD_SCRIPT}"),
603
555
  # scaffold
604
556
  ("Run `python3 ~/.codex/skills/pactkit-scaffold/scripts/scaffold.py", f"Run `{_SCAFFOLD_SCRIPT}"),
605
- # pactkit CLI → manual fallback hint (for commands without script equivalents)
557
+ # pactkit CLI → manual fallback hints (for commands without script equivalents)
606
558
  ("Run `pactkit clean`", "Run language-specific cleanup (e.g., `find . -name '__pycache__' -exec rm -rf {} +` for Python)"),
559
+ ("`pactkit update", "run `pactkit init --format codex` to reinstall"),
560
+ ("`pactkit lint", "run your language linter directly (e.g., `ruff check src/ tests/` for Python)"),
561
+ ("`pactkit regression", "run the full test suite directly (e.g., `python3 -m pytest tests/ -v`)"),
562
+ ("`pactkit context", "update `docs/product/context.md` manually"),
563
+ ("`pactkit guard", "run your linter and test suite directly"),
564
+ ("`pactkit doctor", "check project files and structure manually"),
607
565
  ]
608
566
 
609
567
 
@@ -624,42 +582,6 @@ def _replace_cli_with_scripts(content):
624
582
  return content
625
583
 
626
584
 
627
- def _write_toml_with_markers(path, data):
628
- """Write a dict as TOML with [pactkit:managed] comment markers."""
629
- lines = ["# [pactkit:managed]"]
630
-
631
- for key, value in sorted(data.items()):
632
- if isinstance(value, dict):
633
- continue
634
- lines.append(f'{key} = {_toml_value(value)}')
635
-
636
- lines.append("")
637
-
638
- for key, value in sorted(data.items()):
639
- if not isinstance(value, dict):
640
- continue
641
- if key == "mcp_servers":
642
- lines.append("# [pactkit:managed]")
643
- for sub_key, sub_val in sorted(value.items()):
644
- quoted_sub = _toml_key(sub_key)
645
- if isinstance(sub_val, dict):
646
- lines.append(f"[{key}.{quoted_sub}]")
647
- for k, v in sorted(sub_val.items()):
648
- lines.append(f'{_toml_key(k)} = {_toml_value(v)}')
649
- else:
650
- lines.append(f"[{key}]")
651
- lines.append(f'{quoted_sub} = {_toml_value(sub_val)}')
652
- lines.append("")
653
-
654
- atomic_write(path, "\n".join(lines) + "\n")
655
-
656
-
657
- def _toml_key(key):
658
- """Quote a TOML key if it contains characters outside [A-Za-z0-9_-]."""
659
- if re.fullmatch(r'[A-Za-z0-9_-]+', key):
660
- return key
661
- return f'"{key}"'
662
-
663
585
 
664
586
  def _toml_value(value):
665
587
  """Format a Python value as a TOML value string."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pactkit-codex
3
- Version: 2.10.2
3
+ Version: 2.17.0
4
4
  Summary: PactKit adapter for OpenAI Codex CLI
5
5
  Author: Slim
6
6
  License: MIT
@@ -21,7 +21,7 @@ Classifier: Topic :: Software Development :: Quality Assurance
21
21
  Requires-Python: >=3.10
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
- Requires-Dist: pactkit>=2.9.0
24
+ Requires-Dist: pactkit>=2.17.0
25
25
  Requires-Dist: tomli>=1.1.0; python_version < "3.11"
26
26
  Dynamic: license-file
27
27
 
@@ -1,4 +1,4 @@
1
- pactkit>=2.9.0
1
+ pactkit>=2.17.0
2
2
 
3
3
  [:python_version < "3.11"]
4
4
  tomli>=1.1.0
File without changes
File without changes
File without changes