@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.
- package/.agents/skills/grill-me/SKILL.md +3 -1
- package/.agents/skills/grill-with-docs/SKILL.md +3 -1
- package/.agents/skills/kit-update/SKILL.md +9 -11
- package/.agents/skills/orchestrate-wave/SKILL.md +8 -8
- package/.agents/skills/setup-workflow/SKILL.md +20 -18
- package/.agents/skills/setup-workflow/board-sync.md +4 -1
- package/.agents/skills/setup-workflow/workflow-advisories.md +3 -2
- package/.agents/skills/setup-workflow/worktree-lifecycle.md +36 -31
- package/.agents/skills/to-issues/SKILL.md +43 -0
- package/.agents/skills/wrapup/SKILL.md +98 -54
- package/.claude/skills/grill-me/SKILL.md +3 -1
- package/.claude/skills/grill-me-codex/SKILL.md +3 -1
- package/.claude/skills/grill-with-docs/SKILL.md +3 -1
- package/.claude/skills/grill-with-docs-codex/SKILL.md +3 -1
- package/.claude/skills/kit-update/SKILL.md +9 -11
- package/.claude/skills/orchestrate-wave/SKILL.md +8 -8
- package/.claude/skills/setup-workflow/SKILL.md +20 -18
- package/.claude/skills/setup-workflow/board-sync.md +4 -1
- package/.claude/skills/setup-workflow/workflow-advisories.md +3 -2
- package/.claude/skills/setup-workflow/worktree-lifecycle.md +36 -31
- package/.claude/skills/to-issues/SKILL.md +43 -0
- package/.claude/skills/wrapup/SKILL.md +98 -54
- package/README.md +249 -7
- package/agent-workflow-kit.package.json +42 -42
- package/package.json +16 -12
- package/scripts/marker_lib.py +3 -0
- package/scripts/profile_globs.py +26 -45
- package/scripts/release-delta-guard.mjs +26 -9
- package/scripts/worktree-lifecycle/README.md +57 -160
- package/scripts/worktree-lifecycle/capabilities.json +2 -3
- package/scripts/worktree-lifecycle/classify.py +480 -0
- package/scripts/worktree-lifecycle/cleanup.py +9 -29
- package/scripts/worktree-lifecycle/core.py +68 -1429
- package/scripts/worktree-lifecycle/ignore_seed.py +1 -1
- package/scripts/worktree-lifecycle/profile.py +46 -29
- package/scripts/worktree-lifecycle/setup.py +7 -19
- package/scripts/wrapup-land.py +1292 -545
- package/src/consumer-migrations.json +1 -16
- package/src/lib/bundle.mjs +31 -1
- package/docs/adr/0001-consumer-divergence-policy.md +0 -53
- package/docs/adr/0002-capability-gated-orchestration.md +0 -70
- package/docs/adr/0003-kit-core-and-project-extension-lifecycle.md +0 -63
- package/docs/adr/0004-release-intent-is-a-version-tag.md +0 -64
- package/docs/adr/0005-to-issues-is-the-planning-facade.md +0 -42
- package/docs/adr/0006-routing-knowledge-access-and-policy-are-separate.md +0 -95
- package/docs/adr/0007-session-teardown-requires-provenance-bound-ownership.md +0 -88
- package/docs/adr/0008-planning-ignore-rules-are-offered-never-installed.md +0 -84
- package/docs/adr/0009-teardown-authority-is-stateless-repository-classification.md +0 -101
- package/docs/adr/0010-model-roster-replaces-the-optimization-dial.md +0 -87
- package/docs/agents/board-sync.md +0 -74
- package/docs/agents/code-review.md +0 -14
- package/docs/agents/workflow-capabilities.json +0 -28
- package/docs/research/agent-task-taxonomy-benchmark-coverage.md +0 -451
- package/docs/research/benchlm-routing-source.md +0 -198
- package/docs/research/consumer-owned-protocol-files.md +0 -238
- package/docs/research/frontend-agent-benchmarks.md +0 -282
- package/docs/research/model-effort-routing-benchmarks.md +0 -261
- package/docs/research/provider-neutral-agent-routing.md +0 -207
- package/docs/research/wave-152-consumer-acceptance.md +0 -98
- package/docs/research/wave-43-script-hook-census.md +0 -128
- package/scripts/build-kit.mjs +0 -117
- package/scripts/build-kit.test.mjs +0 -207
- package/scripts/census/census.test.mjs +0 -252
- package/scripts/census/state.test.mjs +0 -15
- package/scripts/census/transaction.test.mjs +0 -103
- package/scripts/census-contract.test.mjs +0 -227
- package/scripts/check-kit-staleness.mjs +0 -45
- package/scripts/check-kit-staleness.test.mjs +0 -19
- package/scripts/codex-exec-scenarios/fake-codex.mjs +0 -165
- package/scripts/codex-exec.test.mjs +0 -871
- package/scripts/grill-census-wiring-guard.mjs +0 -87
- package/scripts/grill-census-wiring-guard.test.mjs +0 -107
- package/scripts/kit-release.test.mjs +0 -273
- package/scripts/kit-update-pr.test.mjs +0 -151
- package/scripts/lib/audit-refs.mjs +0 -146
- package/scripts/lib/scrub.mjs +0 -113
- package/scripts/lib/scrub.test.mjs +0 -187
- package/scripts/memory-lifecycle/memory-lifecycle.test.mjs +0 -170
- package/scripts/portability_profile_scan.py +0 -53
- package/scripts/release-delta-guard.test.mjs +0 -174
- package/scripts/release-parity.test.mjs +0 -90
- package/scripts/release-state.test.mjs +0 -360
- package/scripts/test_anchor_table.py +0 -69
- package/scripts/test_board_bootstrap.py +0 -348
- package/scripts/test_board_sync.py +0 -208
- package/scripts/test_board_sync_create_idempotency.py +0 -117
- package/scripts/test_board_sync_wave_title.py +0 -120
- package/scripts/test_census_backstop.py +0 -712
- package/scripts/test_census_forward_contract.py +0 -91
- package/scripts/test_census_update_contract.test.mjs +0 -454
- package/scripts/test_codex_adapter_sync_contract.py +0 -169
- package/scripts/test_dist_kit_smoke.py +0 -220
- package/scripts/test_drift_guard_diagnostics.py +0 -295
- package/scripts/test_issue_claim_contract.py +0 -169
- package/scripts/test_kit_docs_language_census.py +0 -178
- package/scripts/test_marker_lib.py +0 -162
- package/scripts/test_orchestrate_wave_contract.py +0 -381
- package/scripts/test_pr_body_check.py +0 -264
- package/scripts/test_profile_globs.py +0 -280
- package/scripts/test_program_planning_contract.py +0 -133
- package/scripts/test_release_authorization_contract.py +0 -101
- package/scripts/test_render_anchor.py +0 -267
- package/scripts/test_retro_wrapup_contract.py +0 -153
- package/scripts/test_skill_code_review_seed.py +0 -89
- package/scripts/test_skill_codex_exec_lifecycle.py +0 -123
- package/scripts/test_skill_frontmatter_lint.py +0 -234
- package/scripts/test_skill_gh_lint.py +0 -124
- package/scripts/test_skill_language_census.py +0 -254
- package/scripts/test_skill_optional_readiness.py +0 -171
- package/scripts/test_skill_portability_lint.py +0 -866
- package/scripts/test_skill_precommit_template.py +0 -30
- package/scripts/test_skill_publish_audit.py +0 -358
- package/scripts/test_skill_readiness_contract.py +0 -264
- package/scripts/test_skill_readiness_preflight.py +0 -180
- package/scripts/test_skill_required_readiness.py +0 -233
- package/scripts/test_skill_selfcontainment_lint.py +0 -255
- package/scripts/test_skill_setup_workflow_seeds.py +0 -691
- package/scripts/test_skill_stale_name_lint.py +0 -126
- package/scripts/test_skill_surface_refs.py +0 -300
- package/scripts/test_skill_trailing_artifact_lint.py +0 -71
- package/scripts/test_tdd_contract.py +0 -78
- package/scripts/test_worktree_ignore_seed.py +0 -320
- package/scripts/test_worktree_setup_base_guard.py +0 -140
- package/scripts/test_worktree_wrapup_contract.py +0 -1737
- package/scripts/test_wrapup_land.py +0 -428
- package/scripts/worktree-lifecycle/session.py +0 -1857
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Regression test for marker-aware board issue creation."""
|
|
3
|
-
|
|
4
|
-
from __future__ import annotations
|
|
5
|
-
|
|
6
|
-
import importlib.util
|
|
7
|
-
import json
|
|
8
|
-
import os
|
|
9
|
-
import tempfile
|
|
10
|
-
import unittest
|
|
11
|
-
from pathlib import Path
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
PROFILE = {
|
|
15
|
-
"repo": "example/kit",
|
|
16
|
-
"project": {"number": 1, "owner": "example", "nodeId": "PVT_test"},
|
|
17
|
-
"fields": {
|
|
18
|
-
"status": {"id": "STATUS", "options": {}},
|
|
19
|
-
"wave": "WAVE",
|
|
20
|
-
"cluster": "CLUSTER",
|
|
21
|
-
"specPath": "SPEC",
|
|
22
|
-
"planPath": "PLAN",
|
|
23
|
-
},
|
|
24
|
-
"labels": {
|
|
25
|
-
"readyForAgent": "ready-for-agent",
|
|
26
|
-
"typePrefix": "type:",
|
|
27
|
-
"clusterType": "type:cluster",
|
|
28
|
-
"waveStub": "wave-stub",
|
|
29
|
-
},
|
|
30
|
-
"branchPrefixes": ["feat", "fix"],
|
|
31
|
-
"prMarkers": {"partOf": "Part of", "retroMarker": "Retro", "retroValues": []},
|
|
32
|
-
"headings": {"vorBau": "Clarify Before Build"},
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def load_board_sync():
|
|
37
|
-
previous_profile = os.environ.get("BOARD_SYNC_PROFILE")
|
|
38
|
-
with tempfile.NamedTemporaryFile("w", suffix=".md", delete=False) as profile:
|
|
39
|
-
profile.write("<!-- board-sync:profile -->\n```json\n")
|
|
40
|
-
json.dump(PROFILE, profile)
|
|
41
|
-
profile.write("\n```\n")
|
|
42
|
-
profile_path = profile.name
|
|
43
|
-
os.environ["BOARD_SYNC_PROFILE"] = profile_path
|
|
44
|
-
spec = importlib.util.spec_from_file_location(
|
|
45
|
-
"board_sync_create_test", Path(__file__).with_name("board-sync.py")
|
|
46
|
-
)
|
|
47
|
-
module = importlib.util.module_from_spec(spec)
|
|
48
|
-
assert spec.loader is not None
|
|
49
|
-
try:
|
|
50
|
-
spec.loader.exec_module(module)
|
|
51
|
-
finally:
|
|
52
|
-
Path(profile_path).unlink()
|
|
53
|
-
if previous_profile is None:
|
|
54
|
-
os.environ.pop("BOARD_SYNC_PROFILE", None)
|
|
55
|
-
else:
|
|
56
|
-
os.environ["BOARD_SYNC_PROFILE"] = previous_profile
|
|
57
|
-
return module
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
PROFILE_BEFORE_LOAD = os.environ.get("BOARD_SYNC_PROFILE")
|
|
61
|
-
bs = load_board_sync()
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class FakeGh:
|
|
65
|
-
def __init__(self, marker: str):
|
|
66
|
-
self.marker = marker
|
|
67
|
-
self.created = False
|
|
68
|
-
self.calls: list[list[str]] = []
|
|
69
|
-
|
|
70
|
-
def __call__(self, args: list[str]) -> str:
|
|
71
|
-
self.calls.append(args)
|
|
72
|
-
joined = " ".join(args)
|
|
73
|
-
if "issue list" in joined:
|
|
74
|
-
if not self.created:
|
|
75
|
-
return "[]"
|
|
76
|
-
return json.dumps([
|
|
77
|
-
{
|
|
78
|
-
"number": 101,
|
|
79
|
-
"url": "https://github.com/example/kit/issues/101",
|
|
80
|
-
"body": self.marker,
|
|
81
|
-
}
|
|
82
|
-
])
|
|
83
|
-
if "issue create" in joined:
|
|
84
|
-
self.created = True
|
|
85
|
-
return "https://github.com/example/kit/issues/101\n"
|
|
86
|
-
if "project item-add" in joined:
|
|
87
|
-
return '{"id":"PVTI_test"}'
|
|
88
|
-
return ""
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
class BoardSyncImportIsolationTest(unittest.TestCase):
|
|
92
|
-
def test_loading_board_sync_restores_the_caller_profile(self):
|
|
93
|
-
self.assertEqual(os.environ.get("BOARD_SYNC_PROFILE"), PROFILE_BEFORE_LOAD)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
class MarkerAwareCreateTest(unittest.TestCase):
|
|
97
|
-
def test_identical_program_leaf_retry_reuses_existing_issue(self):
|
|
98
|
-
marker = "<!-- program-leaf-source: program-x/1a -->"
|
|
99
|
-
fake = FakeGh(marker)
|
|
100
|
-
original = bs._gh
|
|
101
|
-
bs._gh = fake
|
|
102
|
-
try:
|
|
103
|
-
with tempfile.NamedTemporaryFile("w", suffix=".md") as body:
|
|
104
|
-
body.write(marker + "\nOutcome: test\n")
|
|
105
|
-
body.flush()
|
|
106
|
-
argv = ["create", "--title", "Slice 1a", "--body-file", body.name]
|
|
107
|
-
self.assertEqual(bs.main(argv), 0)
|
|
108
|
-
self.assertEqual(bs.main(argv), 0)
|
|
109
|
-
finally:
|
|
110
|
-
bs._gh = original
|
|
111
|
-
|
|
112
|
-
creates = [call for call in fake.calls if "issue create" in " ".join(call)]
|
|
113
|
-
self.assertEqual(len(creates), 1)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if __name__ == "__main__":
|
|
117
|
-
unittest.main()
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Wave anchor titles take their prefix from the board profile, not a hardcoded
|
|
3
|
-
German literal — an optional `titles.wavePrefix` key with the literal default
|
|
4
|
-
`"Welle"` so every existing profile keeps working unchanged."""
|
|
5
|
-
|
|
6
|
-
from __future__ import annotations
|
|
7
|
-
|
|
8
|
-
import copy
|
|
9
|
-
import importlib.util
|
|
10
|
-
import json
|
|
11
|
-
import os
|
|
12
|
-
import tempfile
|
|
13
|
-
import unittest
|
|
14
|
-
from pathlib import Path
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
BASE_PROFILE = {
|
|
18
|
-
"repo": "example/kit",
|
|
19
|
-
"project": {"number": 1, "owner": "example", "nodeId": "PVT_test"},
|
|
20
|
-
"fields": {
|
|
21
|
-
"status": {"id": "STATUS", "options": {}},
|
|
22
|
-
"wave": "WAVE",
|
|
23
|
-
"cluster": "CLUSTER",
|
|
24
|
-
"specPath": "SPEC",
|
|
25
|
-
"planPath": "PLAN",
|
|
26
|
-
},
|
|
27
|
-
"labels": {
|
|
28
|
-
"readyForAgent": "ready-for-agent",
|
|
29
|
-
"typePrefix": "type:",
|
|
30
|
-
"clusterType": "type:cluster",
|
|
31
|
-
"waveStub": "wave-stub",
|
|
32
|
-
},
|
|
33
|
-
"branchPrefixes": ["feat", "fix"],
|
|
34
|
-
"prMarkers": {"partOf": "Part of", "retroMarker": "Retro", "retroValues": []},
|
|
35
|
-
"headings": {"vorBau": "Clarify Before Build"},
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def load_board_sync(profile_dict: dict, module_name: str):
|
|
40
|
-
previous_profile = os.environ.get("BOARD_SYNC_PROFILE")
|
|
41
|
-
with tempfile.NamedTemporaryFile("w", suffix=".md", delete=False) as profile:
|
|
42
|
-
profile.write("<!-- board-sync:profile -->\n```json\n")
|
|
43
|
-
json.dump(profile_dict, profile)
|
|
44
|
-
profile.write("\n```\n")
|
|
45
|
-
profile_path = profile.name
|
|
46
|
-
os.environ["BOARD_SYNC_PROFILE"] = profile_path
|
|
47
|
-
spec = importlib.util.spec_from_file_location(
|
|
48
|
-
module_name, Path(__file__).with_name("board-sync.py")
|
|
49
|
-
)
|
|
50
|
-
module = importlib.util.module_from_spec(spec)
|
|
51
|
-
assert spec.loader is not None
|
|
52
|
-
try:
|
|
53
|
-
spec.loader.exec_module(module)
|
|
54
|
-
finally:
|
|
55
|
-
Path(profile_path).unlink()
|
|
56
|
-
if previous_profile is None:
|
|
57
|
-
os.environ.pop("BOARD_SYNC_PROFILE", None)
|
|
58
|
-
else:
|
|
59
|
-
os.environ["BOARD_SYNC_PROFILE"] = previous_profile
|
|
60
|
-
return module
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
class WaveTitleDefaultPrefix(unittest.TestCase):
|
|
64
|
-
"""A profile without `titles.wavePrefix` keeps the historical `Welle` prefix."""
|
|
65
|
-
|
|
66
|
-
@classmethod
|
|
67
|
-
def setUpClass(cls):
|
|
68
|
-
cls.bs = load_board_sync(copy.deepcopy(BASE_PROFILE), "board_sync_wave_default")
|
|
69
|
-
|
|
70
|
-
def test_default_prefix_is_welle(self):
|
|
71
|
-
self.assertEqual(self.bs.wave_title("Auth hardening", 7), "Welle 7 — Auth hardening")
|
|
72
|
-
|
|
73
|
-
def test_repromote_is_idempotent(self):
|
|
74
|
-
self.assertEqual(
|
|
75
|
-
self.bs.wave_title("Welle 7 — Auth hardening", 9),
|
|
76
|
-
"Welle 9 — Auth hardening",
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
def test_conventional_prefix_stripped_before_wave(self):
|
|
80
|
-
self.assertEqual(
|
|
81
|
-
self.bs.wave_title("fix: Welle 7 — Auth hardening", 29),
|
|
82
|
-
"Welle 29 — Auth hardening",
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
def test_loading_board_sync_restores_the_caller_profile(self):
|
|
86
|
-
before = os.environ.get("BOARD_SYNC_PROFILE")
|
|
87
|
-
load_board_sync(copy.deepcopy(BASE_PROFILE), "board_sync_wave_isolation")
|
|
88
|
-
self.assertEqual(os.environ.get("BOARD_SYNC_PROFILE"), before)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
class WaveTitleProfilePrefix(unittest.TestCase):
|
|
92
|
-
"""A profile with `titles.wavePrefix` drives the anchor title language."""
|
|
93
|
-
|
|
94
|
-
@classmethod
|
|
95
|
-
def setUpClass(cls):
|
|
96
|
-
profile = copy.deepcopy(BASE_PROFILE)
|
|
97
|
-
profile["titles"] = {"wavePrefix": "Wave"}
|
|
98
|
-
cls.bs = load_board_sync(profile, "board_sync_wave_custom")
|
|
99
|
-
|
|
100
|
-
def test_configured_prefix_is_used(self):
|
|
101
|
-
self.assertEqual(self.bs.wave_title("Auth hardening", 7), "Wave 7 — Auth hardening")
|
|
102
|
-
|
|
103
|
-
def test_repromote_is_idempotent_for_configured_prefix(self):
|
|
104
|
-
self.assertEqual(
|
|
105
|
-
self.bs.wave_title("Wave 7 — Auth hardening", 9),
|
|
106
|
-
"Wave 9 — Auth hardening",
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
def test_regex_metacharacters_in_prefix_are_literal(self):
|
|
110
|
-
profile = copy.deepcopy(BASE_PROFILE)
|
|
111
|
-
profile["titles"] = {"wavePrefix": "W+A"}
|
|
112
|
-
bs = load_board_sync(profile, "board_sync_wave_meta")
|
|
113
|
-
self.assertEqual(
|
|
114
|
-
bs.wave_title("W+A 3 — Auth hardening", 4),
|
|
115
|
-
"W+A 4 — Auth hardening",
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if __name__ == "__main__":
|
|
120
|
-
unittest.main()
|