@event4u/agent-config 2.6.1 → 2.8.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/.agent-src/commands/agent-handoff.md +1 -0
- package/.agent-src/commands/agent-status.md +1 -0
- package/.agent-src/commands/agents/audit.md +1 -0
- package/.agent-src/commands/agents/init.md +1 -0
- package/.agent-src/commands/agents/optimize.md +1 -0
- package/.agent-src/commands/agents.md +1 -0
- package/.agent-src/commands/analyze-reference-repo.md +1 -0
- package/.agent-src/commands/bug-fix.md +1 -0
- package/.agent-src/commands/bug-investigate.md +1 -0
- package/.agent-src/commands/challenge-me/vision.md +1 -0
- package/.agent-src/commands/challenge-me/with-docs.md +1 -0
- package/.agent-src/commands/challenge-me.md +1 -0
- package/.agent-src/commands/chat-history/import.md +1 -0
- package/.agent-src/commands/chat-history/learn.md +1 -0
- package/.agent-src/commands/chat-history/show.md +1 -0
- package/.agent-src/commands/chat-history.md +1 -0
- package/.agent-src/commands/check-current-md.md +1 -0
- package/.agent-src/commands/commit/in-chunks.md +1 -0
- package/.agent-src/commands/commit.md +1 -0
- package/.agent-src/commands/compress.md +1 -0
- package/.agent-src/commands/context/create.md +1 -0
- package/.agent-src/commands/context/refactor.md +1 -0
- package/.agent-src/commands/context.md +1 -0
- package/.agent-src/commands/cost-report.md +1 -0
- package/.agent-src/commands/council/default.md +1 -0
- package/.agent-src/commands/council/design.md +1 -0
- package/.agent-src/commands/council/optimize.md +1 -0
- package/.agent-src/commands/council/pr.md +1 -0
- package/.agent-src/commands/council.md +1 -0
- package/.agent-src/commands/create-pr/description-only.md +1 -0
- package/.agent-src/commands/create-pr.md +1 -0
- package/.agent-src/commands/e2e-heal.md +1 -0
- package/.agent-src/commands/e2e-plan.md +1 -0
- package/.agent-src/commands/estimate-ticket.md +1 -0
- package/.agent-src/commands/feature/dev.md +1 -0
- package/.agent-src/commands/feature/explore.md +1 -0
- package/.agent-src/commands/feature/plan.md +1 -0
- package/.agent-src/commands/feature/refactor.md +1 -0
- package/.agent-src/commands/feature/roadmap.md +1 -0
- package/.agent-src/commands/feature.md +1 -0
- package/.agent-src/commands/fix/ci.md +1 -0
- package/.agent-src/commands/fix/portability.md +1 -0
- package/.agent-src/commands/fix/pr-bot-comments.md +1 -0
- package/.agent-src/commands/fix/pr-comments.md +1 -0
- package/.agent-src/commands/fix/pr-developer-comments.md +1 -0
- package/.agent-src/commands/fix/refs.md +1 -0
- package/.agent-src/commands/fix/seeder.md +1 -0
- package/.agent-src/commands/fix.md +1 -0
- package/.agent-src/commands/grill-me.md +1 -0
- package/.agent-src/commands/implement-ticket.md +1 -0
- package/.agent-src/commands/jira-ticket.md +1 -0
- package/.agent-src/commands/judge/on-diff.md +1 -0
- package/.agent-src/commands/judge/solo.md +1 -0
- package/.agent-src/commands/judge/steps.md +1 -0
- package/.agent-src/commands/judge.md +1 -0
- package/.agent-src/commands/memory/add.md +1 -0
- package/.agent-src/commands/memory/load.md +1 -0
- package/.agent-src/commands/memory/mine-session.md +1 -0
- package/.agent-src/commands/memory/promote.md +1 -0
- package/.agent-src/commands/memory/propose.md +1 -0
- package/.agent-src/commands/memory.md +1 -0
- package/.agent-src/commands/mode.md +1 -0
- package/.agent-src/commands/module/create.md +1 -0
- package/.agent-src/commands/module/explore.md +1 -0
- package/.agent-src/commands/module.md +1 -0
- package/.agent-src/commands/onboard.md +1 -0
- package/.agent-src/commands/optimize/agents-dir.md +1 -0
- package/.agent-src/commands/optimize/augmentignore.md +1 -0
- package/.agent-src/commands/optimize/rtk.md +1 -0
- package/.agent-src/commands/optimize/skills.md +1 -0
- package/.agent-src/commands/optimize-prompt.md +1 -0
- package/.agent-src/commands/optimize.md +1 -0
- package/.agent-src/commands/orchestrate.md +1 -0
- package/.agent-src/commands/override/create.md +1 -0
- package/.agent-src/commands/override/manage.md +1 -0
- package/.agent-src/commands/override.md +1 -0
- package/.agent-src/commands/package-reset.md +1 -0
- package/.agent-src/commands/package-test.md +1 -0
- package/.agent-src/commands/prepare-for-review.md +1 -0
- package/.agent-src/commands/project-analyze.md +1 -0
- package/.agent-src/commands/project-health.md +1 -0
- package/.agent-src/commands/quality-fix.md +1 -0
- package/.agent-src/commands/refine-ticket.md +1 -0
- package/.agent-src/commands/research/deep.md +1 -0
- package/.agent-src/commands/research/report.md +1 -0
- package/.agent-src/commands/research.md +1 -0
- package/.agent-src/commands/review-changes.md +1 -0
- package/.agent-src/commands/review-routing.md +1 -0
- package/.agent-src/commands/roadmap/ai-council.md +1 -0
- package/.agent-src/commands/roadmap/create.md +1 -0
- package/.agent-src/commands/roadmap/process-full.md +1 -0
- package/.agent-src/commands/roadmap/process-phase.md +1 -0
- package/.agent-src/commands/roadmap/process-step.md +1 -0
- package/.agent-src/commands/roadmap.md +1 -0
- package/.agent-src/commands/rule-compliance-audit.md +1 -0
- package/.agent-src/commands/set-cost-profile.md +1 -0
- package/.agent-src/commands/sync-agent-settings.md +1 -0
- package/.agent-src/commands/sync-gitignore/fix.md +1 -0
- package/.agent-src/commands/sync-gitignore.md +1 -0
- package/.agent-src/commands/tests/create.md +1 -0
- package/.agent-src/commands/tests/execute.md +1 -0
- package/.agent-src/commands/tests.md +1 -0
- package/.agent-src/commands/threat-model.md +1 -0
- package/.agent-src/commands/update-form-request-messages.md +1 -0
- package/.agent-src/commands/upstream-contribute.md +1 -0
- package/.agent-src/commands/work.md +1 -0
- package/.agent-src/personas/cmo.md +122 -0
- package/.agent-src/personas/customer-success-lead.md +126 -0
- package/.agent-src/personas/growth-pm.md +134 -0
- package/.agent-src/personas/revops.md +125 -0
- package/.agent-src/skills/activation-design/SKILL.md +160 -0
- package/.agent-src/skills/churn-prevention/SKILL.md +156 -0
- package/.agent-src/skills/content-funnel-design/SKILL.md +170 -0
- package/.agent-src/skills/deal-qualification-meddic/SKILL.md +165 -0
- package/.agent-src/skills/editorial-calendar/SKILL.md +161 -0
- package/.agent-src/skills/expansion-playbook/SKILL.md +171 -0
- package/.agent-src/skills/forecast-accuracy/SKILL.md +157 -0
- package/.agent-src/skills/fundraising-narrative/SKILL.md +189 -0
- package/.agent-src/skills/funnel-analysis/SKILL.md +26 -2
- package/.agent-src/skills/gtm-launch/SKILL.md +165 -0
- package/.agent-src/skills/messaging-architecture/SKILL.md +184 -0
- package/.agent-src/skills/onboarding-design/SKILL.md +158 -0
- package/.agent-src/skills/pipeline-strategy/SKILL.md +159 -0
- package/.agent-src/skills/positioning-strategy/SKILL.md +177 -0
- package/.agent-src/skills/retention-loops/SKILL.md +161 -0
- package/.agent-src/skills/subagent-orchestration/SKILL.md +1 -1
- package/.agent-src/skills/voice-and-tone-design/SKILL.md +163 -0
- package/.agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/.claude-plugin/marketplace.json +17 -2
- package/AGENTS.md +4 -4
- package/CHANGELOG.md +60 -2257
- package/README.md +59 -33
- package/docs/architecture/augment-projection.md +70 -0
- package/docs/architecture/claude-bundle.md +77 -0
- package/docs/architecture/compression.md +67 -0
- package/docs/architecture/multi-tool-projection.md +72 -0
- package/docs/architecture.md +32 -55
- package/docs/archive/CHANGELOG-pre-2.2.0.md +2138 -0
- package/docs/archive/CHANGELOG-pre-2.7.0.md +185 -0
- package/docs/catalog.md +19 -3
- package/docs/contracts/CHANGELOG-conventions.md +121 -0
- package/docs/contracts/adr-gtm-context-spine.md +115 -0
- package/docs/contracts/command-surface-tiers.md +145 -0
- package/docs/contracts/context-spine.md +50 -12
- package/docs/contracts/cross-wing-handoff.md +3 -3
- package/docs/contracts/mcp-cloud-scope.md +193 -21
- package/docs/contracts/mcp-phase-1-scope.md +1 -0
- package/docs/contracts/persona-schema.md +20 -3
- package/docs/decisions/ADR-007-agent-discovery-scopes.md +67 -0
- package/docs/guidelines/gtm-handoff.md +114 -0
- package/docs/setup/enterprise-and-offline.md +201 -0
- package/docs/setup/per-ide/augment.md +37 -25
- package/package.json +1 -1
- package/scripts/_bootstrap_tier_frontmatter.py +151 -0
- package/scripts/agent-config +146 -83
- package/scripts/hermetic-install.sh +235 -0
- package/scripts/install.py +8 -1
- package/scripts/lint_command_tiers.py +115 -0
- package/scripts/lint_context_spine_usage.py +4 -1
- package/scripts/mcp_server/__init__.py +5 -0
- package/scripts/schemas/command.schema.json +5 -0
- package/scripts/schemas/persona.schema.json +5 -0
- package/scripts/schemas/skill.schema.json +2 -2
- package/scripts/skill_linter.py +177 -3
|
@@ -12,6 +12,11 @@
|
|
|
12
12
|
"pattern": "^[a-z][a-z0-9-]*(:[a-z][a-z0-9-]*)?$",
|
|
13
13
|
"$comment": "Top-level commands use the bare slug (`commit`). Nested cluster commands under `commands/<cluster>/<sub>.md` use the colon form (`council:default`) to mirror Claude Code's `/cluster:sub` rendering. Directory slug for `.claude/skills/` is the hyphenated form (`council-default`), generated by compress.py."
|
|
14
14
|
},
|
|
15
|
+
"tier": {
|
|
16
|
+
"type": "integer",
|
|
17
|
+
"enum": [0, 1, 2],
|
|
18
|
+
"description": "Command-surface tier per docs/contracts/command-surface-tiers.md. 0 = daily-driver (rendered in default `./agent-config --help`), 1 = power-user (rendered with `--tier=1`), 2 = maintenance/internal (rendered only with `--tier=all`). Default for new commands is 2 — promotion is gated by ADR criteria, never by author preference."
|
|
19
|
+
},
|
|
15
20
|
"description": {
|
|
16
21
|
"type": "string",
|
|
17
22
|
"minLength": 1,
|
|
@@ -26,6 +26,11 @@
|
|
|
26
26
|
"type": "string",
|
|
27
27
|
"enum": ["core", "specialist"]
|
|
28
28
|
},
|
|
29
|
+
"wing": {
|
|
30
|
+
"type": "integer",
|
|
31
|
+
"enum": [1, 2, 3, 4],
|
|
32
|
+
"description": "Cognition wing per docs/contracts/package-self-orientation.md § The four wings. Optional. Raises the specialist size cap (persona-schema § 4)."
|
|
33
|
+
},
|
|
29
34
|
"mode": {
|
|
30
35
|
"type": "string",
|
|
31
36
|
"enum": ["developer", "reviewer", "tester", "product-owner", "incident", "planner"]
|
|
@@ -72,9 +72,9 @@
|
|
|
72
72
|
"uniqueItems": true,
|
|
73
73
|
"items": {
|
|
74
74
|
"type": "string",
|
|
75
|
-
"enum": ["product", "team", "repo"]
|
|
75
|
+
"enum": ["product", "team", "repo", "channel-stage", "funnel-stage", "customer-segment"]
|
|
76
76
|
},
|
|
77
|
-
"description": "Senior-skill opt-in for the
|
|
77
|
+
"description": "Senior-skill opt-in for the context spine. Declares which slots under agents/context-spine/ the skill expects to read. Cross-wing slots (product, team, repo) are locked at 3 by council Q1 (KEEP-3); wing-scoped slots (channel-stage, funnel-stage, customer-segment — Wing-3 GTM) follow the per-wing ADR track in docs/contracts/context-spine.md § 5. Wing-3 slots authorized by docs/contracts/adr-gtm-context-spine.md."
|
|
78
78
|
},
|
|
79
79
|
"execution": {
|
|
80
80
|
"type": "object",
|
package/scripts/skill_linter.py
CHANGED
|
@@ -57,6 +57,15 @@ REQUIRED_PERSONA_SECTIONS = REQUIRED_PERSONA_SECTIONS_CORE
|
|
|
57
57
|
VALID_PERSONA_TIERS = {"core", "specialist"}
|
|
58
58
|
# Locked in docs/contracts/persona-schema.md § 4: core ≤ 120, specialist ≤ 100.
|
|
59
59
|
PERSONA_LINE_BUDGETS = {"core": 120, "specialist": 100}
|
|
60
|
+
# Wing-scoped overrides — Wing-3 (GTM) and Wing-4 (Money/Strategy/Ops) carry
|
|
61
|
+
# denser cognition (funnel × channel × lifecycle, or finance × org × strategy)
|
|
62
|
+
# than Wing-1/2 specialists, so the line cap rises to keep the seven-section
|
|
63
|
+
# spine intact without amputating workflows. Persona-schema.md § 4 wing matrix.
|
|
64
|
+
VALID_PERSONA_WINGS = {1, 2, 3, 4}
|
|
65
|
+
PERSONA_LINE_BUDGETS_BY_WING = {
|
|
66
|
+
("specialist", 3): 140,
|
|
67
|
+
("specialist", 4): 140,
|
|
68
|
+
}
|
|
60
69
|
|
|
61
70
|
|
|
62
71
|
REQUIRED_SKILL_SECTIONS = [
|
|
@@ -161,6 +170,47 @@ VALID_EXECUTION_HANDLERS = {"none", "shell", "php", "node", "internal"}
|
|
|
161
170
|
VALID_EXECUTION_SAFETY_MODES = {"strict"}
|
|
162
171
|
VALID_EXECUTION_FIELDS = {"type", "handler", "timeout_seconds", "safety_mode", "allowed_tools", "command"}
|
|
163
172
|
|
|
173
|
+
# --- Wing-3 GTM cognition-boundary patterns (council Q7 / iter-2 OQ3) ---
|
|
174
|
+
# Triggered only when a skill's context_spine declares a Wing-3 slot.
|
|
175
|
+
# See docs/contracts/adr-gtm-context-spine.md and
|
|
176
|
+
# agents/roadmaps/road-to-gtm-and-growth.md § G2.
|
|
177
|
+
WING3_SPINE_SLOTS = {"channel-stage", "funnel-stage", "customer-segment"}
|
|
178
|
+
|
|
179
|
+
CONTEXT_SPINE_INLINE_PATTERN = re.compile(
|
|
180
|
+
r'^context_spine:\s*\[(.*?)\]\s*$', re.MULTILINE
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# agent-operability: external SaaS URLs the agent would have to auth against
|
|
184
|
+
WING3_SAAS_URL_PATTERN = re.compile(
|
|
185
|
+
r"https?://[\w.-]*\.(salesforce|hubspot|marketo|pardot|mailchimp|"
|
|
186
|
+
r"intercom|amplitude|mixpanel|segment|klaviyo|sendgrid|mailgun|"
|
|
187
|
+
r"pendo|gong|outreach|salesloft|apollo)\.(com|io)\b",
|
|
188
|
+
re.IGNORECASE,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
# vendor-independence: brand / SDK / platform slugs that lock cognition
|
|
192
|
+
WING3_VENDOR_BLACKLIST = re.compile(
|
|
193
|
+
r"\b(salesforce|hubspot|marketo|pardot|mailchimp|intercom|drift|"
|
|
194
|
+
r"klaviyo|sendgrid|mailgun|amplitude|mixpanel|pendo|gong|"
|
|
195
|
+
r"outreach\.io|salesloft|apollo\.io|zendesk|freshworks)\b",
|
|
196
|
+
re.IGNORECASE,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
# transferability: stack-locked tooling instructions
|
|
200
|
+
WING3_STACK_LOCKED_PATTERN = re.compile(
|
|
201
|
+
r"\b(npm install|pip install|composer require|gem install|"
|
|
202
|
+
r"cargo add|yarn add|pnpm add|bundle add)\s+[\w@/.-]+",
|
|
203
|
+
re.IGNORECASE,
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
# channel-agnosticism: channel-specific tactical prescriptions
|
|
207
|
+
WING3_CHANNEL_TACTIC_PATTERN = re.compile(
|
|
208
|
+
r"\b(email subject line|tweet length|linkedin (post|ad)|"
|
|
209
|
+
r"facebook ad|google ads?|tiktok (post|video)|instagram (post|reel)|"
|
|
210
|
+
r"sms character limit|cold email template)\b",
|
|
211
|
+
re.IGNORECASE,
|
|
212
|
+
)
|
|
213
|
+
|
|
164
214
|
|
|
165
215
|
@dataclass
|
|
166
216
|
class Issue:
|
|
@@ -605,6 +655,11 @@ def lint_skill(path: Path, text: str) -> LintResult:
|
|
|
605
655
|
if tier_match and tier_match.group(1) == "senior":
|
|
606
656
|
issues.extend(lint_senior_tier_blocks(text))
|
|
607
657
|
|
|
658
|
+
# --- Wing-3 GTM cognition-boundary check (council Q7 / adr-gtm-context-spine.md) ---
|
|
659
|
+
spine_slots = parse_context_spine(frontmatter)
|
|
660
|
+
if spine_slots and any(s in WING3_SPINE_SLOTS for s in spine_slots):
|
|
661
|
+
issues.extend(lint_wing3_boundaries(text))
|
|
662
|
+
|
|
608
663
|
procedure_block = find_procedure_block(text)
|
|
609
664
|
if procedure_block is not None:
|
|
610
665
|
if not procedure_block:
|
|
@@ -993,6 +1048,98 @@ def lint_senior_tier_blocks(text: str) -> List[Issue]:
|
|
|
993
1048
|
return issues
|
|
994
1049
|
|
|
995
1050
|
|
|
1051
|
+
def parse_context_spine(frontmatter: str) -> Optional[List[str]]:
|
|
1052
|
+
"""Parse `context_spine:` from frontmatter.
|
|
1053
|
+
|
|
1054
|
+
Supports the inline form `context_spine: [a, b, c]` (most skills) and
|
|
1055
|
+
the block form via `_parse_yaml_list`. Returns the slot list, ``[]``
|
|
1056
|
+
for an explicitly empty array, or ``None`` if the key is absent.
|
|
1057
|
+
"""
|
|
1058
|
+
match = CONTEXT_SPINE_INLINE_PATTERN.search(frontmatter)
|
|
1059
|
+
if match is not None:
|
|
1060
|
+
inner = match.group(1).strip()
|
|
1061
|
+
if not inner:
|
|
1062
|
+
return []
|
|
1063
|
+
return [s.strip().strip('"').strip("'") for s in inner.split(",") if s.strip()]
|
|
1064
|
+
block = _parse_yaml_list(frontmatter, "context_spine")
|
|
1065
|
+
return block
|
|
1066
|
+
|
|
1067
|
+
|
|
1068
|
+
def _strip_wing3_carve_outs(text: str) -> str:
|
|
1069
|
+
"""Remove fenced code, inline backticks, the ``## Do NOT`` block, and
|
|
1070
|
+
``**WHEN NOT to use this**`` bullets so legitimate citations of vendor
|
|
1071
|
+
names (as off-scope examples) do not trip Wing-3 boundary checks.
|
|
1072
|
+
"""
|
|
1073
|
+
text = re.sub(r"```[^\n]*\n.*?```", "", text, flags=re.DOTALL)
|
|
1074
|
+
text = re.sub(r"`[^`]+`", "", text)
|
|
1075
|
+
text = re.sub(
|
|
1076
|
+
r"^##\s+Do NOT\s*$.*?(?=^##\s+|\Z)",
|
|
1077
|
+
"", text, flags=re.MULTILINE | re.DOTALL,
|
|
1078
|
+
)
|
|
1079
|
+
text = re.sub(
|
|
1080
|
+
r"\*\*WHEN NOT to use this\*\*.*?(?=\*\*WHEN|^##\s+|\Z)",
|
|
1081
|
+
"", text, flags=re.DOTALL | re.IGNORECASE,
|
|
1082
|
+
)
|
|
1083
|
+
return text
|
|
1084
|
+
|
|
1085
|
+
|
|
1086
|
+
def lint_wing3_boundaries(text: str) -> List[Issue]:
|
|
1087
|
+
"""Four Wing-3 GTM cognition-boundary checks.
|
|
1088
|
+
|
|
1089
|
+
Triggered when a skill's ``context_spine`` declares at least one
|
|
1090
|
+
Wing-3 slot (channel-stage, funnel-stage, customer-segment). Enforces
|
|
1091
|
+
council Q7 / iter-2 OQ3 verdict that GTM cognition stays:
|
|
1092
|
+
|
|
1093
|
+
- **agent-operability** — no external SaaS URLs the agent would auth against.
|
|
1094
|
+
- **vendor-independence** — no platform / SDK / brand slugs.
|
|
1095
|
+
- **transferability** — no stack-locked tooling instructions.
|
|
1096
|
+
- **channel-agnosticism** — no channel-specific tactical prescriptions.
|
|
1097
|
+
|
|
1098
|
+
Carve-outs: fenced code, inline backticks, the ``## Do NOT`` block,
|
|
1099
|
+
and ``**WHEN NOT to use this**`` lists — so authors can cite a vendor
|
|
1100
|
+
as off-scope without tripping the linter.
|
|
1101
|
+
"""
|
|
1102
|
+
issues: List[Issue] = []
|
|
1103
|
+
body = _strip_wing3_carve_outs(text)
|
|
1104
|
+
|
|
1105
|
+
match = WING3_SAAS_URL_PATTERN.search(body)
|
|
1106
|
+
if match:
|
|
1107
|
+
issues.append(Issue(
|
|
1108
|
+
"warning", "wing3_agent_operability",
|
|
1109
|
+
f"Wing-3 skill cites external SaaS URL `{match.group(0)}` outside "
|
|
1110
|
+
f"carve-outs — cognition skills must operate without SaaS auth "
|
|
1111
|
+
f"(council Q7 boundary)",
|
|
1112
|
+
))
|
|
1113
|
+
|
|
1114
|
+
match = WING3_VENDOR_BLACKLIST.search(body)
|
|
1115
|
+
if match:
|
|
1116
|
+
issues.append(Issue(
|
|
1117
|
+
"warning", "wing3_vendor_independence",
|
|
1118
|
+
f"Wing-3 skill names vendor `{match.group(0)}` outside carve-outs "
|
|
1119
|
+
f"— keep cognition vendor-agnostic (council Q7 boundary)",
|
|
1120
|
+
))
|
|
1121
|
+
|
|
1122
|
+
match = WING3_STACK_LOCKED_PATTERN.search(body)
|
|
1123
|
+
if match:
|
|
1124
|
+
issues.append(Issue(
|
|
1125
|
+
"warning", "wing3_transferability",
|
|
1126
|
+
f"Wing-3 skill includes stack-locked instruction `{match.group(0)}` "
|
|
1127
|
+
f"outside carve-outs — cognition should transfer across stacks "
|
|
1128
|
+
f"(council Q7 boundary)",
|
|
1129
|
+
))
|
|
1130
|
+
|
|
1131
|
+
match = WING3_CHANNEL_TACTIC_PATTERN.search(body)
|
|
1132
|
+
if match:
|
|
1133
|
+
issues.append(Issue(
|
|
1134
|
+
"warning", "wing3_channel_agnosticism",
|
|
1135
|
+
f"Wing-3 skill prescribes channel-specific tactic "
|
|
1136
|
+
f"`{match.group(0)}` outside carve-outs — keep cognition "
|
|
1137
|
+
f"channel-agnostic (council Q7 boundary)",
|
|
1138
|
+
))
|
|
1139
|
+
|
|
1140
|
+
return issues
|
|
1141
|
+
|
|
1142
|
+
|
|
996
1143
|
def lint_execution_metadata(execution: dict) -> List[Issue]:
|
|
997
1144
|
"""Validate the execution block of a skill."""
|
|
998
1145
|
issues: List[Issue] = []
|
|
@@ -1436,6 +1583,27 @@ def lint_persona(path: Path, text: str) -> LintResult:
|
|
|
1436
1583
|
f"Persona tier `{parsed['tier']}` must be one of {sorted(VALID_PERSONA_TIERS)}",
|
|
1437
1584
|
))
|
|
1438
1585
|
|
|
1586
|
+
# wing — optional; when present must be one of {1,2,3,4} (per
|
|
1587
|
+
# docs/contracts/package-self-orientation.md § The four wings).
|
|
1588
|
+
wing_match = re.search(r'^wing:\s*"?(\d+)"?\s*$', frontmatter, re.MULTILINE)
|
|
1589
|
+
if wing_match:
|
|
1590
|
+
try:
|
|
1591
|
+
wing_value = int(wing_match.group(1))
|
|
1592
|
+
if wing_value in VALID_PERSONA_WINGS:
|
|
1593
|
+
parsed["wing"] = wing_value
|
|
1594
|
+
else:
|
|
1595
|
+
issues.append(Issue(
|
|
1596
|
+
"error",
|
|
1597
|
+
"invalid_wing",
|
|
1598
|
+
f"Persona wing `{wing_value}` must be one of {sorted(VALID_PERSONA_WINGS)}",
|
|
1599
|
+
))
|
|
1600
|
+
except ValueError:
|
|
1601
|
+
issues.append(Issue(
|
|
1602
|
+
"error",
|
|
1603
|
+
"invalid_wing",
|
|
1604
|
+
f"Persona wing `{wing_match.group(1)}` must be an integer 1–4",
|
|
1605
|
+
))
|
|
1606
|
+
|
|
1439
1607
|
# description length
|
|
1440
1608
|
if "description" in parsed and len(parsed["description"]) > 160:
|
|
1441
1609
|
issues.append(Issue(
|
|
@@ -1473,15 +1641,21 @@ def lint_persona(path: Path, text: str) -> LintResult:
|
|
|
1473
1641
|
f"Persona has {bullet_count} unique questions (target ≥ 3)",
|
|
1474
1642
|
))
|
|
1475
1643
|
|
|
1476
|
-
# Size budget by tier
|
|
1644
|
+
# Size budget by tier — wing-overrides apply when the persona declares a
|
|
1645
|
+
# `wing:` field; defaults to the tier baseline otherwise.
|
|
1477
1646
|
if "tier" in parsed and parsed["tier"] in PERSONA_LINE_BUDGETS:
|
|
1478
|
-
|
|
1647
|
+
tier_value = parsed["tier"]
|
|
1648
|
+
wing_value = parsed.get("wing")
|
|
1649
|
+
budget = PERSONA_LINE_BUDGETS_BY_WING.get(
|
|
1650
|
+
(tier_value, wing_value), PERSONA_LINE_BUDGETS[tier_value]
|
|
1651
|
+
)
|
|
1479
1652
|
line_count = len(text.splitlines())
|
|
1480
1653
|
if line_count > budget:
|
|
1654
|
+
scope = f"{tier_value}" if wing_value is None else f"{tier_value}, wing {wing_value}"
|
|
1481
1655
|
issues.append(Issue(
|
|
1482
1656
|
"warning",
|
|
1483
1657
|
"size_budget",
|
|
1484
|
-
f"Persona has {line_count} lines ({
|
|
1658
|
+
f"Persona has {line_count} lines ({scope} budget ≤ {budget})",
|
|
1485
1659
|
))
|
|
1486
1660
|
|
|
1487
1661
|
# H1 heading
|