@ikon85/agent-workflow-kit 0.43.0 → 0.44.1

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 (127) 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/skill-manifest.json +1 -1
  22. package/.claude/skills/to-issues/SKILL.md +43 -0
  23. package/.claude/skills/wrapup/SKILL.md +98 -54
  24. package/README.md +254 -7
  25. package/agent-workflow-kit.package.json +43 -43
  26. package/package.json +16 -12
  27. package/scripts/marker_lib.py +3 -0
  28. package/scripts/profile_globs.py +26 -45
  29. package/scripts/release-delta-guard.mjs +26 -9
  30. package/scripts/worktree-lifecycle/README.md +57 -160
  31. package/scripts/worktree-lifecycle/capabilities.json +2 -3
  32. package/scripts/worktree-lifecycle/classify.py +480 -0
  33. package/scripts/worktree-lifecycle/cleanup.py +9 -29
  34. package/scripts/worktree-lifecycle/core.py +68 -1429
  35. package/scripts/worktree-lifecycle/ignore_seed.py +1 -1
  36. package/scripts/worktree-lifecycle/profile.py +46 -29
  37. package/scripts/worktree-lifecycle/setup.py +7 -19
  38. package/scripts/wrapup-land.py +1292 -545
  39. package/src/consumer-migrations.json +1 -16
  40. package/src/lib/bundle.mjs +31 -1
  41. package/docs/adr/0001-consumer-divergence-policy.md +0 -53
  42. package/docs/adr/0002-capability-gated-orchestration.md +0 -70
  43. package/docs/adr/0003-kit-core-and-project-extension-lifecycle.md +0 -63
  44. package/docs/adr/0004-release-intent-is-a-version-tag.md +0 -64
  45. package/docs/adr/0005-to-issues-is-the-planning-facade.md +0 -42
  46. package/docs/adr/0006-routing-knowledge-access-and-policy-are-separate.md +0 -95
  47. package/docs/adr/0007-session-teardown-requires-provenance-bound-ownership.md +0 -88
  48. package/docs/adr/0008-planning-ignore-rules-are-offered-never-installed.md +0 -84
  49. package/docs/adr/0009-teardown-authority-is-stateless-repository-classification.md +0 -101
  50. package/docs/adr/0010-model-roster-replaces-the-optimization-dial.md +0 -87
  51. package/docs/agents/board-sync.md +0 -74
  52. package/docs/agents/code-review.md +0 -14
  53. package/docs/agents/workflow-capabilities.json +0 -28
  54. package/docs/research/agent-task-taxonomy-benchmark-coverage.md +0 -451
  55. package/docs/research/benchlm-routing-source.md +0 -198
  56. package/docs/research/consumer-owned-protocol-files.md +0 -238
  57. package/docs/research/frontend-agent-benchmarks.md +0 -282
  58. package/docs/research/model-effort-routing-benchmarks.md +0 -261
  59. package/docs/research/provider-neutral-agent-routing.md +0 -207
  60. package/docs/research/wave-152-consumer-acceptance.md +0 -98
  61. package/docs/research/wave-43-script-hook-census.md +0 -128
  62. package/scripts/build-kit.mjs +0 -117
  63. package/scripts/build-kit.test.mjs +0 -207
  64. package/scripts/census/census.test.mjs +0 -252
  65. package/scripts/census/state.test.mjs +0 -15
  66. package/scripts/census/transaction.test.mjs +0 -103
  67. package/scripts/census-contract.test.mjs +0 -227
  68. package/scripts/check-kit-staleness.mjs +0 -45
  69. package/scripts/check-kit-staleness.test.mjs +0 -19
  70. package/scripts/codex-exec-scenarios/fake-codex.mjs +0 -165
  71. package/scripts/codex-exec.test.mjs +0 -871
  72. package/scripts/grill-census-wiring-guard.mjs +0 -87
  73. package/scripts/grill-census-wiring-guard.test.mjs +0 -107
  74. package/scripts/kit-release.test.mjs +0 -273
  75. package/scripts/kit-update-pr.test.mjs +0 -151
  76. package/scripts/lib/audit-refs.mjs +0 -146
  77. package/scripts/lib/scrub.mjs +0 -113
  78. package/scripts/lib/scrub.test.mjs +0 -187
  79. package/scripts/memory-lifecycle/memory-lifecycle.test.mjs +0 -170
  80. package/scripts/portability_profile_scan.py +0 -53
  81. package/scripts/release-delta-guard.test.mjs +0 -174
  82. package/scripts/release-parity.test.mjs +0 -90
  83. package/scripts/release-state.test.mjs +0 -360
  84. package/scripts/test_anchor_table.py +0 -69
  85. package/scripts/test_board_bootstrap.py +0 -348
  86. package/scripts/test_board_sync.py +0 -208
  87. package/scripts/test_board_sync_create_idempotency.py +0 -117
  88. package/scripts/test_board_sync_wave_title.py +0 -120
  89. package/scripts/test_census_backstop.py +0 -712
  90. package/scripts/test_census_forward_contract.py +0 -91
  91. package/scripts/test_census_update_contract.test.mjs +0 -454
  92. package/scripts/test_codex_adapter_sync_contract.py +0 -169
  93. package/scripts/test_dist_kit_smoke.py +0 -220
  94. package/scripts/test_drift_guard_diagnostics.py +0 -295
  95. package/scripts/test_issue_claim_contract.py +0 -169
  96. package/scripts/test_kit_docs_language_census.py +0 -178
  97. package/scripts/test_marker_lib.py +0 -162
  98. package/scripts/test_orchestrate_wave_contract.py +0 -381
  99. package/scripts/test_pr_body_check.py +0 -264
  100. package/scripts/test_profile_globs.py +0 -280
  101. package/scripts/test_program_planning_contract.py +0 -133
  102. package/scripts/test_release_authorization_contract.py +0 -101
  103. package/scripts/test_render_anchor.py +0 -267
  104. package/scripts/test_retro_wrapup_contract.py +0 -153
  105. package/scripts/test_skill_code_review_seed.py +0 -89
  106. package/scripts/test_skill_codex_exec_lifecycle.py +0 -123
  107. package/scripts/test_skill_frontmatter_lint.py +0 -234
  108. package/scripts/test_skill_gh_lint.py +0 -124
  109. package/scripts/test_skill_language_census.py +0 -254
  110. package/scripts/test_skill_optional_readiness.py +0 -171
  111. package/scripts/test_skill_portability_lint.py +0 -866
  112. package/scripts/test_skill_precommit_template.py +0 -30
  113. package/scripts/test_skill_publish_audit.py +0 -358
  114. package/scripts/test_skill_readiness_contract.py +0 -264
  115. package/scripts/test_skill_readiness_preflight.py +0 -180
  116. package/scripts/test_skill_required_readiness.py +0 -233
  117. package/scripts/test_skill_selfcontainment_lint.py +0 -255
  118. package/scripts/test_skill_setup_workflow_seeds.py +0 -691
  119. package/scripts/test_skill_stale_name_lint.py +0 -126
  120. package/scripts/test_skill_surface_refs.py +0 -300
  121. package/scripts/test_skill_trailing_artifact_lint.py +0 -71
  122. package/scripts/test_tdd_contract.py +0 -78
  123. package/scripts/test_worktree_ignore_seed.py +0 -320
  124. package/scripts/test_worktree_setup_base_guard.py +0 -140
  125. package/scripts/test_worktree_wrapup_contract.py +0 -1737
  126. package/scripts/test_wrapup_land.py +0 -428
  127. 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