@ikon85/agent-workflow-kit 0.43.0 → 0.44.0

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.
Files changed (126) hide show
  1. package/.agents/skills/grill-me/SKILL.md +3 -1
  2. package/.agents/skills/grill-with-docs/SKILL.md +3 -1
  3. package/.agents/skills/kit-update/SKILL.md +9 -11
  4. package/.agents/skills/orchestrate-wave/SKILL.md +8 -8
  5. package/.agents/skills/setup-workflow/SKILL.md +20 -18
  6. package/.agents/skills/setup-workflow/board-sync.md +4 -1
  7. package/.agents/skills/setup-workflow/workflow-advisories.md +3 -2
  8. package/.agents/skills/setup-workflow/worktree-lifecycle.md +36 -31
  9. package/.agents/skills/to-issues/SKILL.md +43 -0
  10. package/.agents/skills/wrapup/SKILL.md +98 -54
  11. package/.claude/skills/grill-me/SKILL.md +3 -1
  12. package/.claude/skills/grill-me-codex/SKILL.md +3 -1
  13. package/.claude/skills/grill-with-docs/SKILL.md +3 -1
  14. package/.claude/skills/grill-with-docs-codex/SKILL.md +3 -1
  15. package/.claude/skills/kit-update/SKILL.md +9 -11
  16. package/.claude/skills/orchestrate-wave/SKILL.md +8 -8
  17. package/.claude/skills/setup-workflow/SKILL.md +20 -18
  18. package/.claude/skills/setup-workflow/board-sync.md +4 -1
  19. package/.claude/skills/setup-workflow/workflow-advisories.md +3 -2
  20. package/.claude/skills/setup-workflow/worktree-lifecycle.md +36 -31
  21. package/.claude/skills/to-issues/SKILL.md +43 -0
  22. package/.claude/skills/wrapup/SKILL.md +98 -54
  23. package/README.md +249 -7
  24. package/agent-workflow-kit.package.json +42 -42
  25. package/package.json +16 -12
  26. package/scripts/marker_lib.py +3 -0
  27. package/scripts/profile_globs.py +26 -45
  28. package/scripts/release-delta-guard.mjs +26 -9
  29. package/scripts/worktree-lifecycle/README.md +57 -160
  30. package/scripts/worktree-lifecycle/capabilities.json +2 -3
  31. package/scripts/worktree-lifecycle/classify.py +480 -0
  32. package/scripts/worktree-lifecycle/cleanup.py +9 -29
  33. package/scripts/worktree-lifecycle/core.py +68 -1429
  34. package/scripts/worktree-lifecycle/ignore_seed.py +1 -1
  35. package/scripts/worktree-lifecycle/profile.py +46 -29
  36. package/scripts/worktree-lifecycle/setup.py +7 -19
  37. package/scripts/wrapup-land.py +1292 -545
  38. package/src/consumer-migrations.json +1 -16
  39. package/src/lib/bundle.mjs +31 -1
  40. package/docs/adr/0001-consumer-divergence-policy.md +0 -53
  41. package/docs/adr/0002-capability-gated-orchestration.md +0 -70
  42. package/docs/adr/0003-kit-core-and-project-extension-lifecycle.md +0 -63
  43. package/docs/adr/0004-release-intent-is-a-version-tag.md +0 -64
  44. package/docs/adr/0005-to-issues-is-the-planning-facade.md +0 -42
  45. package/docs/adr/0006-routing-knowledge-access-and-policy-are-separate.md +0 -95
  46. package/docs/adr/0007-session-teardown-requires-provenance-bound-ownership.md +0 -88
  47. package/docs/adr/0008-planning-ignore-rules-are-offered-never-installed.md +0 -84
  48. package/docs/adr/0009-teardown-authority-is-stateless-repository-classification.md +0 -101
  49. package/docs/adr/0010-model-roster-replaces-the-optimization-dial.md +0 -87
  50. package/docs/agents/board-sync.md +0 -74
  51. package/docs/agents/code-review.md +0 -14
  52. package/docs/agents/workflow-capabilities.json +0 -28
  53. package/docs/research/agent-task-taxonomy-benchmark-coverage.md +0 -451
  54. package/docs/research/benchlm-routing-source.md +0 -198
  55. package/docs/research/consumer-owned-protocol-files.md +0 -238
  56. package/docs/research/frontend-agent-benchmarks.md +0 -282
  57. package/docs/research/model-effort-routing-benchmarks.md +0 -261
  58. package/docs/research/provider-neutral-agent-routing.md +0 -207
  59. package/docs/research/wave-152-consumer-acceptance.md +0 -98
  60. package/docs/research/wave-43-script-hook-census.md +0 -128
  61. package/scripts/build-kit.mjs +0 -117
  62. package/scripts/build-kit.test.mjs +0 -207
  63. package/scripts/census/census.test.mjs +0 -252
  64. package/scripts/census/state.test.mjs +0 -15
  65. package/scripts/census/transaction.test.mjs +0 -103
  66. package/scripts/census-contract.test.mjs +0 -227
  67. package/scripts/check-kit-staleness.mjs +0 -45
  68. package/scripts/check-kit-staleness.test.mjs +0 -19
  69. package/scripts/codex-exec-scenarios/fake-codex.mjs +0 -165
  70. package/scripts/codex-exec.test.mjs +0 -871
  71. package/scripts/grill-census-wiring-guard.mjs +0 -87
  72. package/scripts/grill-census-wiring-guard.test.mjs +0 -107
  73. package/scripts/kit-release.test.mjs +0 -273
  74. package/scripts/kit-update-pr.test.mjs +0 -151
  75. package/scripts/lib/audit-refs.mjs +0 -146
  76. package/scripts/lib/scrub.mjs +0 -113
  77. package/scripts/lib/scrub.test.mjs +0 -187
  78. package/scripts/memory-lifecycle/memory-lifecycle.test.mjs +0 -170
  79. package/scripts/portability_profile_scan.py +0 -53
  80. package/scripts/release-delta-guard.test.mjs +0 -174
  81. package/scripts/release-parity.test.mjs +0 -90
  82. package/scripts/release-state.test.mjs +0 -360
  83. package/scripts/test_anchor_table.py +0 -69
  84. package/scripts/test_board_bootstrap.py +0 -348
  85. package/scripts/test_board_sync.py +0 -208
  86. package/scripts/test_board_sync_create_idempotency.py +0 -117
  87. package/scripts/test_board_sync_wave_title.py +0 -120
  88. package/scripts/test_census_backstop.py +0 -712
  89. package/scripts/test_census_forward_contract.py +0 -91
  90. package/scripts/test_census_update_contract.test.mjs +0 -454
  91. package/scripts/test_codex_adapter_sync_contract.py +0 -169
  92. package/scripts/test_dist_kit_smoke.py +0 -220
  93. package/scripts/test_drift_guard_diagnostics.py +0 -295
  94. package/scripts/test_issue_claim_contract.py +0 -169
  95. package/scripts/test_kit_docs_language_census.py +0 -178
  96. package/scripts/test_marker_lib.py +0 -162
  97. package/scripts/test_orchestrate_wave_contract.py +0 -381
  98. package/scripts/test_pr_body_check.py +0 -264
  99. package/scripts/test_profile_globs.py +0 -280
  100. package/scripts/test_program_planning_contract.py +0 -133
  101. package/scripts/test_release_authorization_contract.py +0 -101
  102. package/scripts/test_render_anchor.py +0 -267
  103. package/scripts/test_retro_wrapup_contract.py +0 -153
  104. package/scripts/test_skill_code_review_seed.py +0 -89
  105. package/scripts/test_skill_codex_exec_lifecycle.py +0 -123
  106. package/scripts/test_skill_frontmatter_lint.py +0 -234
  107. package/scripts/test_skill_gh_lint.py +0 -124
  108. package/scripts/test_skill_language_census.py +0 -254
  109. package/scripts/test_skill_optional_readiness.py +0 -171
  110. package/scripts/test_skill_portability_lint.py +0 -866
  111. package/scripts/test_skill_precommit_template.py +0 -30
  112. package/scripts/test_skill_publish_audit.py +0 -358
  113. package/scripts/test_skill_readiness_contract.py +0 -264
  114. package/scripts/test_skill_readiness_preflight.py +0 -180
  115. package/scripts/test_skill_required_readiness.py +0 -233
  116. package/scripts/test_skill_selfcontainment_lint.py +0 -255
  117. package/scripts/test_skill_setup_workflow_seeds.py +0 -691
  118. package/scripts/test_skill_stale_name_lint.py +0 -126
  119. package/scripts/test_skill_surface_refs.py +0 -300
  120. package/scripts/test_skill_trailing_artifact_lint.py +0 -71
  121. package/scripts/test_tdd_contract.py +0 -78
  122. package/scripts/test_worktree_ignore_seed.py +0 -320
  123. package/scripts/test_worktree_setup_base_guard.py +0 -140
  124. package/scripts/test_worktree_wrapup_contract.py +0 -1737
  125. package/scripts/test_wrapup_land.py +0 -428
  126. package/scripts/worktree-lifecycle/session.py +0 -1857
@@ -5,7 +5,7 @@ The shipped skills write `PLAN.md`, `PLAN-REVIEW-LOG.md`, and `ANNAHMEN.md`
5
5
  into a session worktree, but `.gitignore` is a consumer file the kit does not
6
6
  own: `init` and `update` never touch it. This helper is the one place that
7
7
  closes that gap, and it closes it only when a user explicitly approves the
8
- offer inside `/setup-workflow` (ADR 0008).
8
+ offer inside `/setup-workflow`.
9
9
 
10
10
  Contract:
11
11
 
@@ -1,4 +1,21 @@
1
- """Worktree Lifecycle profile loading and low-level git operations."""
1
+ """Worktree Lifecycle profile loading and low-level git operations.
2
+
3
+ The profile carries **structural facts only** — worktree root, naming
4
+ templates, the protected branches, the setup sequence. Deletion policy has
5
+ exactly one configuration surface, the ignore mechanism, so no pattern list is
6
+ read here. Keys this loader does not know are ignored in silence: a profile
7
+ written for an older kit keeps working, and an obsolete key produces no warning
8
+ noise.
9
+
10
+ Two branch templates exist because two kinds of work land. `branchTemplate`
11
+ names the branch of an issue-anchored slice; `contentBranchTemplate` names the
12
+ issue-less branch a session cuts for durable content, so it renders `{type}`
13
+ and `{slug}` only and refuses `{issue}` outright rather than inventing a number.
14
+
15
+ `DEFAULT_MAIN_BRANCHES` is the single place in the kit that names an
16
+ integration branch at all; every command, test, and message resolves the name
17
+ through the profile instead of assuming it.
18
+ """
2
19
 
3
20
  from __future__ import annotations
4
21
 
@@ -9,6 +26,9 @@ from dataclasses import dataclass
9
26
  from pathlib import Path
10
27
  from typing import Any
11
28
 
29
+ DEFAULT_MAIN_BRANCHES = ("main", "master")
30
+ DEFAULT_CONTENT_BRANCH_TEMPLATE = "{type}/{slug}"
31
+
12
32
 
13
33
  class LifecycleError(RuntimeError):
14
34
  """A safe, user-visible lifecycle refusal."""
@@ -18,6 +38,7 @@ class LifecycleError(RuntimeError):
18
38
  class WorktreeProfile:
19
39
  root: str
20
40
  branch_template: str
41
+ content_branch_template: str
21
42
  path_template: str
22
43
  main_branches: tuple[str, ...]
23
44
  protected_branches: tuple[str, ...]
@@ -25,15 +46,16 @@ class WorktreeProfile:
25
46
  branch_regex: str
26
47
  setup_entry: str
27
48
  risky_command_patterns: tuple[str, ...]
28
- scratch_patterns: tuple[str, ...]
29
- landing_generated_artifact_policy_configured: bool
30
- landing_generated_artifact_patterns: tuple[str, ...]
31
49
 
32
50
  def branch_name(self, issue: str, slug: str, branch_type: str) -> str:
33
- return _render(self.branch_template, issue, slug, branch_type)
51
+ return _render(self.branch_template, issue=issue, slug=slug, type=branch_type)
52
+
53
+ def content_branch_name(self, slug: str, branch_type: str) -> str:
54
+ """Name the issue-less branch of a Content-route session."""
55
+ return render_content_branch(self.content_branch_template, slug, branch_type)
34
56
 
35
57
  def relative_path(self, issue: str, slug: str, branch_type: str) -> Path:
36
- name = _render(self.path_template, issue, slug, branch_type)
58
+ name = _render(self.path_template, issue=issue, slug=slug, type=branch_type)
37
59
  return Path(self.root) / name
38
60
 
39
61
  def issue_from_branch(self, branch: str) -> str | None:
@@ -41,14 +63,25 @@ class WorktreeProfile:
41
63
  return match.groupdict().get("issue") if match else None
42
64
 
43
65
 
44
- def _render(template: str, issue: str, slug: str, branch_type: str) -> str:
45
- values = {"issue": issue, "slug": slug, "type": branch_type}
66
+ def _render(template: str, **values: str) -> str:
67
+ """Render a profile template from exactly the placeholders it may use."""
46
68
  try:
47
69
  return template.format(**values)
48
- except (KeyError, ValueError) as error:
70
+ except (KeyError, IndexError, ValueError) as error:
49
71
  raise LifecycleError(f"invalid worktree template: {error}") from error
50
72
 
51
73
 
74
+ def render_content_branch(template: str, slug: str, branch_type: str) -> str:
75
+ """Render one issue-less content branch name — the placeholder policy's home.
76
+
77
+ A caller that reads the template out of a raw profile document (wrapup's
78
+ Content route does, because it must work whether or not the worktree
79
+ lifecycle itself is enabled) renders it here, so `{issue}` is refused in
80
+ exactly one place instead of two.
81
+ """
82
+ return _render(template, slug=slug, type=branch_type)
83
+
84
+
52
85
  def _load_profile_document(document: Any) -> WorktreeProfile:
53
86
  try:
54
87
  raw = document["worktreeLifecycle"]
@@ -56,26 +89,13 @@ def _load_profile_document(document: Any) -> WorktreeProfile:
56
89
  raise LifecycleError(f"cannot load worktree lifecycle profile: {error}") from error
57
90
  if raw.get("enabled") is not True:
58
91
  raise LifecycleError("worktree lifecycle is not enabled")
59
- wrapup = document.get("wrapup")
60
- if wrapup is None:
61
- wrapup = {}
62
- if not isinstance(wrapup, dict):
63
- raise LifecycleError("invalid wrapup profile")
64
- generated_policy_configured = "landingGeneratedArtifactPatterns" in wrapup
65
- generated_patterns = (
66
- wrapup["landingGeneratedArtifactPatterns"]
67
- if generated_policy_configured
68
- else ()
69
- )
70
- if (
71
- not isinstance(generated_patterns, (list, tuple))
72
- or not all(isinstance(pattern, str) and pattern for pattern in generated_patterns)
73
- ):
74
- raise LifecycleError("invalid wrapup landingGeneratedArtifactPatterns")
75
- main = tuple(raw.get("mainBranches") or ("main", "master"))
92
+ main = tuple(raw.get("mainBranches") or DEFAULT_MAIN_BRANCHES)
76
93
  return WorktreeProfile(
77
94
  root=raw.get("worktreeRoot", ".worktrees"),
78
95
  branch_template=raw.get("branchTemplate", "{type}/{issue}-{slug}"),
96
+ content_branch_template=raw.get(
97
+ "contentBranchTemplate", DEFAULT_CONTENT_BRANCH_TEMPLATE,
98
+ ),
79
99
  path_template=raw.get("pathTemplate", "{type}-{issue}-{slug}"),
80
100
  main_branches=main,
81
101
  protected_branches=tuple(raw.get("protectedBranches") or main),
@@ -92,9 +112,6 @@ def _load_profile_document(document: Any) -> WorktreeProfile:
92
112
  r"\b(?:npm|pnpm|yarn)\s+(?:run\s+)?(?:test|typecheck|build)\b",
93
113
  r"\bgit\s+(?:commit|push)\b",
94
114
  )),
95
- scratch_patterns=tuple(raw.get("scratchPatterns") or ()),
96
- landing_generated_artifact_policy_configured=generated_policy_configured,
97
- landing_generated_artifact_patterns=tuple(generated_patterns),
98
115
  )
99
116
 
100
117
 
@@ -10,9 +10,6 @@ import zlib
10
10
  from pathlib import Path
11
11
 
12
12
  from core import (
13
- BaselineBackfillDeferred,
14
- capture_artifact_baseline,
15
- ensure_artifact_baseline,
16
13
  LifecycleError,
17
14
  load_profile,
18
15
  local_branch_exists,
@@ -25,7 +22,9 @@ from core import (
25
22
  def parse_args() -> argparse.Namespace:
26
23
  parser = argparse.ArgumentParser()
27
24
  parser.add_argument("--profile", default="docs/agents/workflow-capabilities.json")
28
- parser.add_argument("--base", default="origin/main")
25
+ # Resolved from the consumer profile when omitted — the integration
26
+ # branch is never named inline.
27
+ parser.add_argument("--base")
29
28
  parser.add_argument("issue")
30
29
  parser.add_argument("slug")
31
30
  parser.add_argument("branch_type", nargs="?", default="feat")
@@ -133,34 +132,24 @@ def create(args: argparse.Namespace) -> Path:
133
132
  if not profile_path.is_absolute():
134
133
  profile_path = main / profile_path
135
134
  profile = load_profile(profile_path)
135
+ base = args.base or f"origin/{profile.main_branches[0]}"
136
136
  branch = profile.branch_name(args.issue, args.slug, args.branch_type)
137
137
  target = (main / profile.relative_path(args.issue, args.slug, args.branch_type)).resolve()
138
138
 
139
139
  if target in registered_worktrees(main):
140
140
  ensure_reusable_base(
141
- main, repo=target, rev="HEAD", base=args.base, label=f"worktree {target}"
141
+ main, repo=target, rev="HEAD", base=base, label=f"worktree {target}"
142
142
  )
143
- try:
144
- ensure_artifact_baseline(
145
- target,
146
- reject_ignored_patterns=profile.landing_generated_artifact_patterns,
147
- )
148
- except BaselineBackfillDeferred as error:
149
- print(
150
- "Baseline backfill deferred; preserve the worktree, remove generated "
151
- f"blockers or commit/stash tracked work, then retry: {error}",
152
- file=sys.stderr,
153
- )
154
143
  print(f"Worktree already exists: {target} ({branch})")
155
144
  return target
156
145
 
157
146
  branch_existed = local_branch_exists(main, branch)
158
147
  if branch_existed:
159
148
  ensure_reusable_base(
160
- main, repo=main, rev=branch, base=args.base, label=f"branch {branch}"
149
+ main, repo=main, rev=branch, base=base, label=f"branch {branch}"
161
150
  )
162
151
  command = ["git", "worktree", "add", str(target)]
163
- command += [branch] if branch_existed else ["-b", branch, args.base]
152
+ command += [branch] if branch_existed else ["-b", branch, base]
164
153
  run(command, cwd=main)
165
154
  try:
166
155
  for step in profile.setup_steps:
@@ -171,7 +160,6 @@ def create(args: argparse.Namespace) -> Path:
171
160
  issue=args.issue,
172
161
  branch=branch,
173
162
  )
174
- capture_artifact_baseline(target)
175
163
  except Exception:
176
164
  remove_failed_worktree(main, target, branch, not branch_existed)
177
165
  raise