@danmoisan/drm-copilot-mcp 1.0.11 → 1.0.13
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/out/mcp-server.js +585 -123
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +4 -3
- package/resources/claude-customizations/.claude/hooks/persist-session-id.ps1 +153 -0
- package/resources/claude-customizations/.claude/settings.json +13 -0
- package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +51 -24
- package/resources/claude-customizations/.claude/skills/identify-session-id/SKILL.md +44 -0
- package/resources/claude-customizations/.claude/skills/show-my-agent-tree/SKILL.md +39 -0
- package/resources/claude-customizations/pack-manifests/core.json +3 -0
- package/resources/feature-templates/epic/epic-status.md +20 -0
- package/resources/feature-templates/epic/epic.md +79 -0
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +4 -0
- package/resources/templates/new-claude-worktree-session.ps1 +58 -9
- package/resources/feature-templates/epic/initiative.md +0 -43
package/package.json
CHANGED
|
@@ -63,7 +63,7 @@ On every invocation:
|
|
|
63
63
|
`git branch`, and `gh pr view --json state,mergedAt,headRefOid` per the `epic-orchestrate`
|
|
64
64
|
skill's resume procedure, not from in-memory notifications alone).
|
|
65
65
|
5. If no checkpoint exists or the objective is new, begin from manifest parsing
|
|
66
|
-
(`docs/features/epics/<epic-slug>/epic
|
|
66
|
+
(`docs/features/epics/<epic-slug>/epic.md`).
|
|
67
67
|
|
|
68
68
|
## Delegation Model
|
|
69
69
|
|
|
@@ -112,8 +112,9 @@ route's required names from `config/orchestration-routing.json`.
|
|
|
112
112
|
Maintain `docs/features/epics/<epic-slug>/epic-status.md` as a human-readable projection of the
|
|
113
113
|
epic checkpoint's `features[]` array, regenerated (not hand-edited) at epic kickoff, at every
|
|
114
114
|
`merge_status` transition, at every wave transition, and at final integration-PR completion, per
|
|
115
|
-
the `epic-orchestrate` skill's documentation-maintenance procedure. `epic
|
|
116
|
-
manifest) is treated as static, human-authored input and is not
|
|
115
|
+
the `epic-orchestrate` skill's documentation-maintenance procedure. `epic.md` itself (the merged
|
|
116
|
+
manifest + narrative source of truth) is treated as static, human-authored input and is not
|
|
117
|
+
rewritten by you; `epic-status.md` is a generated projection only and is never hand-authored.
|
|
117
118
|
|
|
118
119
|
## Completion Requirements
|
|
119
120
|
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
SessionStart hook that persists the current Claude Code session id.
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Invoked by the Claude Code SessionStart hook event (registered in
|
|
7
|
+
.claude/settings.json). Reads the hook payload JSON from standard input,
|
|
8
|
+
falling back to the CLAUDE_HOOK_INPUT environment variable (the existing
|
|
9
|
+
SubagentStop-hook precedent), and extracts the 'session_id' field.
|
|
10
|
+
|
|
11
|
+
Persistence channel:
|
|
12
|
+
- When CLAUDE_ENV_FILE is set, appends the line
|
|
13
|
+
'CLAUDE_SESSION_ID=<id>' to that file. Variables persisted there are
|
|
14
|
+
exported to subsequent Bash tool commands in the session, which is how
|
|
15
|
+
this hook provisions the otherwise-unset CLAUDE_SESSION_ID variable.
|
|
16
|
+
- When CLAUDE_ENV_FILE is unset, writes the id to
|
|
17
|
+
.claude/state/current-session-id instead.
|
|
18
|
+
|
|
19
|
+
On malformed or empty input (missing/blank payload, unparseable JSON, or an
|
|
20
|
+
absent/blank session_id) the hook performs no write. It always exits 0 so a
|
|
21
|
+
SessionStart hook never blocks session start.
|
|
22
|
+
|
|
23
|
+
.NOTES
|
|
24
|
+
Compatible with PowerShell 7+. Does not use Invoke-Expression.
|
|
25
|
+
#>
|
|
26
|
+
[CmdletBinding()]
|
|
27
|
+
param()
|
|
28
|
+
|
|
29
|
+
function Get-PersistSessionIdDecision {
|
|
30
|
+
[CmdletBinding()]
|
|
31
|
+
[OutputType([System.Collections.Specialized.OrderedDictionary])]
|
|
32
|
+
param(
|
|
33
|
+
[string] $RawPayload,
|
|
34
|
+
|
|
35
|
+
[string] $EnvFilePath,
|
|
36
|
+
|
|
37
|
+
[Parameter(Mandatory)]
|
|
38
|
+
[string] $StateFilePath
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
$none = [ordered]@{ action = 'none'; sessionId = ''; path = '' }
|
|
42
|
+
|
|
43
|
+
if ([string]::IsNullOrWhiteSpace($RawPayload)) {
|
|
44
|
+
return $none
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
$payload = $RawPayload | ConvertFrom-Json -ErrorAction Stop
|
|
49
|
+
} catch {
|
|
50
|
+
Write-Verbose "persist-session-id: ignoring unparseable payload: $($_.Exception.Message)"
|
|
51
|
+
return $none
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
$sessionId = $null
|
|
55
|
+
if ($null -ne $payload -and $payload.PSObject.Properties.Name -contains 'session_id') {
|
|
56
|
+
$sessionId = [string]$payload.session_id
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if ([string]::IsNullOrWhiteSpace($sessionId)) {
|
|
60
|
+
return $none
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (-not [string]::IsNullOrWhiteSpace($EnvFilePath)) {
|
|
64
|
+
return [ordered]@{ action = 'env-file'; sessionId = $sessionId; path = $EnvFilePath }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return [ordered]@{ action = 'state-file'; sessionId = $sessionId; path = $StateFilePath }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function Invoke-PersistSessionIdHook {
|
|
71
|
+
[CmdletBinding()]
|
|
72
|
+
[OutputType([System.Collections.Specialized.OrderedDictionary])]
|
|
73
|
+
param(
|
|
74
|
+
[string] $RawPayload,
|
|
75
|
+
|
|
76
|
+
[string] $EnvFilePath,
|
|
77
|
+
|
|
78
|
+
[Parameter(Mandatory)]
|
|
79
|
+
[string] $StateFilePath,
|
|
80
|
+
|
|
81
|
+
[scriptblock] $AppendLine = {
|
|
82
|
+
param([string] $Path, [string] $Line)
|
|
83
|
+
Add-Content -Path $Path -Value $Line -Encoding utf8
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
[scriptblock] $WriteStateFile = {
|
|
87
|
+
param([string] $Path, [string] $Content)
|
|
88
|
+
Set-Content -Path $Path -Value $Content -Encoding utf8 -NoNewline
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
[scriptblock] $EnsureDirectory = {
|
|
92
|
+
param([string] $Path)
|
|
93
|
+
if (-not (Test-Path -Path $Path)) {
|
|
94
|
+
New-Item -ItemType Directory -Path $Path -Force | Out-Null
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
$decision = Get-PersistSessionIdDecision -RawPayload $RawPayload -EnvFilePath $EnvFilePath -StateFilePath $StateFilePath
|
|
100
|
+
|
|
101
|
+
switch ($decision.action) {
|
|
102
|
+
'env-file' {
|
|
103
|
+
& $AppendLine $decision.path ("CLAUDE_SESSION_ID={0}" -f $decision.sessionId)
|
|
104
|
+
}
|
|
105
|
+
'state-file' {
|
|
106
|
+
$stateDir = Split-Path -Path $decision.path -Parent
|
|
107
|
+
if ($stateDir) {
|
|
108
|
+
& $EnsureDirectory $stateDir
|
|
109
|
+
}
|
|
110
|
+
& $WriteStateFile $decision.path $decision.sessionId
|
|
111
|
+
}
|
|
112
|
+
default {
|
|
113
|
+
# 'none': malformed or empty input; perform no write.
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return $decision
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function Read-HookPayload {
|
|
121
|
+
[CmdletBinding()]
|
|
122
|
+
[OutputType([string])]
|
|
123
|
+
param(
|
|
124
|
+
[scriptblock] $ReadStandardInput = { [Console]::In.ReadToEnd() },
|
|
125
|
+
|
|
126
|
+
[AllowNull()]
|
|
127
|
+
[AllowEmptyString()]
|
|
128
|
+
[string] $FallbackPayload = $env:CLAUDE_HOOK_INPUT
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
$raw = ''
|
|
132
|
+
try {
|
|
133
|
+
$raw = & $ReadStandardInput
|
|
134
|
+
} catch {
|
|
135
|
+
$raw = ''
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if ([string]::IsNullOrWhiteSpace($raw)) {
|
|
139
|
+
return $FallbackPayload
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return $raw
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if ($MyInvocation.InvocationName -eq '.') {
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
$rawPayload = Read-HookPayload
|
|
150
|
+
$stateFilePath = Join-Path -Path (Get-Location).Path -ChildPath '.claude/state/current-session-id'
|
|
151
|
+
Invoke-PersistSessionIdHook -RawPayload $rawPayload -EnvFilePath $env:CLAUDE_ENV_FILE -StateFilePath $stateFilePath | Out-Null
|
|
152
|
+
|
|
153
|
+
exit 0
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"mcp__drm-copilot__new_active_feature_folder",
|
|
23
23
|
"mcp__drm-copilot__validate_orchestration_artifacts",
|
|
24
24
|
"mcp__drm-copilot__resolve_atomic_plan_prompt",
|
|
25
|
+
"mcp__drm-copilot__render_subagent_tree",
|
|
25
26
|
"Agent(atomic-planner)",
|
|
26
27
|
"Agent(atomic-executor)",
|
|
27
28
|
"Agent(feature-review)",
|
|
@@ -55,6 +56,8 @@
|
|
|
55
56
|
"Skill(invoke-powershell-engineer *)",
|
|
56
57
|
"Skill(translate-copilot-to-claude *)",
|
|
57
58
|
"Skill(execute-hard-lock *)",
|
|
59
|
+
"Skill(identify-session-id *)",
|
|
60
|
+
"Skill(show-my-agent-tree *)",
|
|
58
61
|
"Edit(/.claude/skills/execute-hard-lock/**)",
|
|
59
62
|
"Edit(/.claude/skills/feature-review-workflow/**)",
|
|
60
63
|
"Edit(/.claude/skills/csharp-qa-gate/**)"
|
|
@@ -71,6 +74,16 @@
|
|
|
71
74
|
]
|
|
72
75
|
},
|
|
73
76
|
"hooks": {
|
|
77
|
+
"SessionStart": [
|
|
78
|
+
{
|
|
79
|
+
"hooks": [
|
|
80
|
+
{
|
|
81
|
+
"type": "command",
|
|
82
|
+
"command": "pwsh -NoProfile -File .claude/hooks/persist-session-id.ps1"
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
],
|
|
74
87
|
"PreToolUse": [
|
|
75
88
|
{
|
|
76
89
|
"matcher": "Bash",
|
|
@@ -22,10 +22,12 @@ Before proceeding, `epic-orchestrator` must:
|
|
|
22
22
|
|
|
23
23
|
## Epic Dependency Manifest
|
|
24
24
|
|
|
25
|
-
The epic manifest is
|
|
26
|
-
`docs/features/epics/<epic-slug>/epic
|
|
27
|
-
|
|
28
|
-
narrative (goal, scope, non-goals
|
|
25
|
+
The epic manifest is the YAML frontmatter of the single epic home
|
|
26
|
+
`docs/features/epics/<epic-slug>/epic.md`. `epic.md` is the merged source of truth: its
|
|
27
|
+
frontmatter carries the fields that must be parsed deterministically, and the Markdown body
|
|
28
|
+
below the frontmatter carries the single free-text epic narrative (goal, scope, non-goals,
|
|
29
|
+
shared design, decomposition) that is not machine-parsed. `epic.md` is also the source from
|
|
30
|
+
which the epic GitHub issue body is generated.
|
|
29
31
|
|
|
30
32
|
Frontmatter schema:
|
|
31
33
|
|
|
@@ -34,19 +36,37 @@ Frontmatter schema:
|
|
|
34
36
|
epic: <epic-slug>
|
|
35
37
|
integration_branch: epic/<epic-slug>-integration
|
|
36
38
|
created_at: <iso8601>
|
|
39
|
+
# Optional additive SAFe-style intent block. Omit the whole block when unused; when
|
|
40
|
+
# present, epic_type and business_outcome_hypothesis are required and
|
|
41
|
+
# leading_indicators / nfrs are optional lists of strings.
|
|
42
|
+
intent:
|
|
43
|
+
epic_type: <business | enabler>
|
|
44
|
+
business_outcome_hypothesis: <measurable outcome the epic is expected to move>
|
|
45
|
+
leading_indicators: [<early validation signal>, ...]
|
|
46
|
+
nfrs: [<non-functional requirement>, ...]
|
|
37
47
|
features:
|
|
38
|
-
-
|
|
39
|
-
|
|
40
|
-
depends_on: [<
|
|
48
|
+
- issue_num: <int>
|
|
49
|
+
feature_folder: <resolvable-hint-basename>
|
|
50
|
+
depends_on: [<upstream-issue_num>, ...]
|
|
41
51
|
---
|
|
42
52
|
```
|
|
43
53
|
|
|
44
|
-
- `
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
54
|
+
- `issue_num` is the primary key: the stable GitHub issue number for the child feature. The
|
|
55
|
+
DAG is keyed by `issue_num`, so it does not drift when a child is promoted from `active/` to
|
|
56
|
+
`completed/`.
|
|
57
|
+
- `feature_folder` is a resolvable hint, not a stable identifier. It may resolve to a concrete
|
|
58
|
+
path under `docs/features/active/<basename>` or `docs/features/completed/<basename>`; a
|
|
59
|
+
lifecycle prefix is stripped to the basename during resolution.
|
|
60
|
+
- `depends_on` is an array of `issue_num` values (legacy manifests may still use
|
|
61
|
+
`feature_folder` basenames). Each entry must resolve — via the union index of the
|
|
62
|
+
`issue_num` set plus the `feature_folder` set — to another entry in `features[]`. A
|
|
63
|
+
`depends_on` entry that does not resolve, or a duplicate `feature_folder` value, is a
|
|
64
|
+
malformed manifest and is rejected before epic kickoff as a synthetic Blocking finding —
|
|
65
|
+
`epic-orchestrator` does not guess.
|
|
66
|
+
- The optional `intent` block is additive and presence-gated: when present it is validated
|
|
67
|
+
(`epic_type` in {business, enabler}, non-empty `business_outcome_hypothesis`, string-list
|
|
68
|
+
`leading_indicators` / `nfrs`); when absent, validation is byte-identical to a manifest
|
|
69
|
+
without it.
|
|
50
70
|
|
|
51
71
|
## Wave Assignment
|
|
52
72
|
|
|
@@ -137,10 +157,14 @@ When `epic-orchestrator` kicks off a feature with a non-empty `depends_on`, the
|
|
|
137
157
|
includes one literal citation line per dependency, appended after the epic-mode kickoff line
|
|
138
158
|
above:
|
|
139
159
|
|
|
140
|
-
> `Upstream context for <
|
|
160
|
+
> `Upstream context for <issue_num>: depends on <dep_issue_num> (spec: <dep_resolved_folder>/spec.md; plan: <dep_resolved_folder>/plan.<ts>.md; merged as PR #<dep_pr_number>, commit <dep_merge_commit_sha>, into <integration_branch>).`
|
|
141
161
|
|
|
142
|
-
`epic-orchestrator` resolves
|
|
143
|
-
`features[]` records
|
|
162
|
+
`epic-orchestrator` resolves each dependency by its stable `issue_num` against its own
|
|
163
|
+
checkpoint's `features[]` records, and resolves `<dep_resolved_folder>` to the dependency's
|
|
164
|
+
concrete `feature_folder` path — under `docs/features/active/` or `docs/features/completed/`
|
|
165
|
+
depending on the dependency's current lifecycle state at emit time — before emitting the line.
|
|
166
|
+
Because the DAG is keyed by `issue_num`, no active→completed path-drift workaround is needed: the
|
|
167
|
+
concrete path is resolved from the checkpoint's current state, so the dependent feature's own
|
|
144
168
|
`orchestrator`/`atomic-planner` is told exactly which upstream artifacts are relevant rather than
|
|
145
169
|
being expected to rediscover prior design decisions from the diff alone.
|
|
146
170
|
|
|
@@ -207,12 +231,13 @@ child worktree) issues `git worktree remove <worktree_path>`, gated by
|
|
|
207
231
|
|
|
208
232
|
## Documentation Maintenance Boundaries
|
|
209
233
|
|
|
210
|
-
`epic
|
|
211
|
-
status document) are kept distinct. `epic
|
|
212
|
-
static input; automatic epic decomposition is out of scope, so this
|
|
213
|
-
rewritten. `epic-
|
|
214
|
-
|
|
215
|
-
|
|
234
|
+
`epic.md` (the merged manifest + narrative source of truth) and `epic-status.md` (a separate,
|
|
235
|
+
epic-orchestrator-maintained status document) are kept distinct. `epic.md`'s frontmatter is the
|
|
236
|
+
human-authored, largely static input; automatic epic decomposition is out of scope, so this
|
|
237
|
+
file is not repeatedly rewritten. `epic-status.md` is a generated projection only: it is
|
|
238
|
+
regenerated (never hand-authored) from the epic checkpoint and is never the source of the DAG.
|
|
239
|
+
`epic-orchestrator` maintains `docs/features/epics/<epic-slug>/epic-status.md`, regenerated from
|
|
240
|
+
the epic checkpoint at each of the following boundaries, not only at final completion:
|
|
216
241
|
|
|
217
242
|
- Epic kickoff — initial status table seeded from the manifest (one row per feature: wave,
|
|
218
243
|
status `not_started`).
|
|
@@ -229,12 +254,14 @@ checkpoint JSON remains the durable, machine-authoritative source.
|
|
|
229
254
|
## Epic-Level Checkpoint
|
|
230
255
|
|
|
231
256
|
`artifacts/orchestration/epic-orchestrator-state.json` carries `objective`, `route_id: "epic"`,
|
|
232
|
-
`epic_feature_folder`, `epic_manifest_path
|
|
257
|
+
`epic_feature_folder`, `epic_manifest_path` (which points at
|
|
258
|
+
`docs/features/epics/<epic-slug>/epic.md`), `epic_status_doc_path`, `integration_branch`,
|
|
233
259
|
`completed_steps`, `next_step`, `last_updated`, `current_wave`, `waves[]`, `features[]`,
|
|
234
260
|
`epic_merge_pr`, and the three receipt arrays (`delegation_receipts[]`, `skill_receipts[]`,
|
|
235
261
|
`mcp_call_receipts[]`) — the full schema is defined in `spec.md` §6 of this feature. The
|
|
236
262
|
`merge_status` enum is: `not_started`, `worktree_created`, `pr_open`, `ci_green`,
|
|
237
|
-
`merge_conflict`, `blocked_conflict_loop_limit`, `merged`, `worktree_removed`.
|
|
263
|
+
`merge_conflict`, `blocked_conflict_loop_limit`, `merged`, `worktree_removed`. The optional
|
|
264
|
+
`intent` object (projection of the `epic.md` intent block) is validated presence-gated.
|
|
238
265
|
|
|
239
266
|
Every field needed to re-derive state durably on resume (`worktree_path`, `branch_name`,
|
|
240
267
|
`pr_number`, `merge_status`) is re-derivable from `git worktree list --porcelain`, `git branch`,
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: identify-session-id
|
|
3
|
+
description: Resolve the current Claude Code session id (the root transcript filename stem) without human input, using an ordered fallback chain, and report which source supplied it. Use before any workflow that needs the running session's id (for example show-my-agent-tree).
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Bash
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Identify Session Id
|
|
10
|
+
|
|
11
|
+
Resolve the current session's id — the root transcript filename stem under
|
|
12
|
+
`~/.claude/projects/<encoded-workspace>/` — without asking the human. Try the
|
|
13
|
+
sources in order and stop at the first that yields a non-empty id. Always
|
|
14
|
+
report which source was used.
|
|
15
|
+
|
|
16
|
+
## Resolution Order
|
|
17
|
+
|
|
18
|
+
1. **Environment variable (primary).** Read `CLAUDE_SESSION_ID` from the
|
|
19
|
+
environment with a single command, e.g.:
|
|
20
|
+
- Bash: `printf '%s' "$CLAUDE_SESSION_ID"`
|
|
21
|
+
- pwsh: `pwsh -NoProfile -Command 'Write-Output $env:CLAUDE_SESSION_ID'`
|
|
22
|
+
|
|
23
|
+
This variable is provisioned by the SessionStart hook
|
|
24
|
+
`.claude/hooks/persist-session-id.ps1` through the `CLAUDE_ENV_FILE`
|
|
25
|
+
channel. If it is non-empty, use it and report source `env:CLAUDE_SESSION_ID`.
|
|
26
|
+
|
|
27
|
+
2. **State file (secondary).** Read `.claude/state/current-session-id`
|
|
28
|
+
(written by the same hook when `CLAUDE_ENV_FILE` is unset). If it exists and
|
|
29
|
+
is non-empty, use its trimmed contents and report source
|
|
30
|
+
`.claude/state/current-session-id`.
|
|
31
|
+
|
|
32
|
+
3. **Newest transcript (tertiary heuristic).** List the root `*.jsonl` files
|
|
33
|
+
directly under `~/.claude/projects/<encodeWorkspacePath(cwd)>/` (the encoding
|
|
34
|
+
replaces every path separator and `:` with `-`), pick the one with the
|
|
35
|
+
newest modification time, and use its filename stem (without `.jsonl`).
|
|
36
|
+
Report source `newest-mtime transcript` and note that this heuristic can
|
|
37
|
+
pick the wrong sibling only when multiple concurrent sessions share one
|
|
38
|
+
workspace path.
|
|
39
|
+
|
|
40
|
+
## Output
|
|
41
|
+
|
|
42
|
+
Report the resolved session id and the source that supplied it, for example:
|
|
43
|
+
`session_id = <id> (source: env:CLAUDE_SESSION_ID)`. If every source is empty,
|
|
44
|
+
state that the session id could not be resolved and which sources were checked.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: show-my-agent-tree
|
|
3
|
+
description: Render the current session's subagent call tree and print it in the assistant reply. Use when the user asks to "show my agent tree" or otherwise wants to see the subagent hierarchy of the running session.
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Bash
|
|
7
|
+
- mcp__drm-copilot__render_subagent_tree
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Show My Agent Tree
|
|
11
|
+
|
|
12
|
+
Render the subagent call tree for the current session and print it directly in
|
|
13
|
+
the assistant reply. This works identically in normal turns and in `/btw`
|
|
14
|
+
side-conversations and needs no VS Code host API.
|
|
15
|
+
|
|
16
|
+
## Flow
|
|
17
|
+
|
|
18
|
+
1. **Resolve the session id.** Follow the `identify-session-id` skill to obtain
|
|
19
|
+
the current session id and note which source supplied it.
|
|
20
|
+
|
|
21
|
+
2. **Call the MCP tool.** Invoke `mcp__drm-copilot__render_subagent_tree` with:
|
|
22
|
+
- `session_id`: the id resolved in step 1.
|
|
23
|
+
- `workspace_root`: an explicit absolute path to the current workspace root
|
|
24
|
+
(do not rely on the tool's default; pass it explicitly).
|
|
25
|
+
|
|
26
|
+
On success the tool returns `ok: true`, a `summary` naming the session id
|
|
27
|
+
and resolved transcript path, and a `rendered_tree` string.
|
|
28
|
+
|
|
29
|
+
3. **Print the tree.** Output the `rendered_tree` value in the assistant reply
|
|
30
|
+
inside a fenced code block, so the hierarchy is legible. Include the
|
|
31
|
+
`summary` line above it for context.
|
|
32
|
+
|
|
33
|
+
## Error Handling
|
|
34
|
+
|
|
35
|
+
- If the tool returns `ok: false`, report the `summary` verbatim. An unknown
|
|
36
|
+
session id names the searched directories; a malformed session id names the
|
|
37
|
+
validation rule (`^[0-9A-Za-z-]{8,64}$`).
|
|
38
|
+
- If `identify-session-id` cannot resolve an id, report that and do not call
|
|
39
|
+
the tool.
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
".claude/hooks/enforce-pr-author-skill.ps1",
|
|
29
29
|
".claude/hooks/enforce-prd-feature-before-planner.ps1",
|
|
30
30
|
".claude/hooks/enforce-promotion-mcp-only.ps1",
|
|
31
|
+
".claude/hooks/persist-session-id.ps1",
|
|
31
32
|
".claude/hooks/validate-bash.ps1",
|
|
32
33
|
".claude/hooks/validate-executor-output.ps1",
|
|
33
34
|
".claude/hooks/validate-feature-review-coverage.ps1",
|
|
@@ -55,6 +56,7 @@
|
|
|
55
56
|
".claude/skills/fill-feature-docs/SKILL.md",
|
|
56
57
|
".claude/skills/human-exception-runbook/example.runbook.md",
|
|
57
58
|
".claude/skills/human-exception-runbook/SKILL.md",
|
|
59
|
+
".claude/skills/identify-session-id/SKILL.md",
|
|
58
60
|
".claude/skills/make-skill-template/SKILL.md",
|
|
59
61
|
".claude/skills/orchestrate/SKILL.md",
|
|
60
62
|
".claude/skills/policy-audit-template-usage/SKILL.md",
|
|
@@ -67,6 +69,7 @@
|
|
|
67
69
|
".claude/skills/review-epic/SKILL.md",
|
|
68
70
|
".claude/skills/review-feature/SKILL.md",
|
|
69
71
|
".claude/skills/review-staged/SKILL.md",
|
|
72
|
+
".claude/skills/show-my-agent-tree/SKILL.md",
|
|
70
73
|
".claude/skills/skill-canonical-location-audit/SKILL.md",
|
|
71
74
|
".claude/skills/translate-copilot-to-claude/SKILL.md",
|
|
72
75
|
".claude/skills/update-status/SKILL.md",
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
GENERATED FILE — DO NOT HAND-AUTHOR.
|
|
3
|
+
|
|
4
|
+
epic-status.md is a generated projection of the epic checkpoint
|
|
5
|
+
(artifacts/orchestration/epic-orchestrator-state.json). It is regenerated by
|
|
6
|
+
the epic-orchestrator agent at each lifecycle boundary (epic kickoff, every
|
|
7
|
+
feature merge_status change, each wave transition, and final integration
|
|
8
|
+
merge). It is never the source of the dependency DAG and must never be edited
|
|
9
|
+
by hand — the manifest in epic.md and the epic checkpoint JSON are the
|
|
10
|
+
authoritative sources.
|
|
11
|
+
-->
|
|
12
|
+
|
|
13
|
+
# <epic-name> - Epic Status (generated)
|
|
14
|
+
|
|
15
|
+
This document is regenerated from the epic checkpoint and must not be
|
|
16
|
+
hand-authored. Any manual edit will be overwritten on the next regeneration.
|
|
17
|
+
|
|
18
|
+
| feature_folder | issue_num | wave_number | merge_status | pr_url | merge_commit_sha |
|
|
19
|
+
| --- | --- | --- | --- | --- | --- |
|
|
20
|
+
| _(populated on epic kickoff from the manifest, then updated in place)_ | | | | | |
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Epic manifest (source of truth).
|
|
3
|
+
#
|
|
4
|
+
# This YAML frontmatter is the machine-readable manifest for the epic: the
|
|
5
|
+
# dependency DAG (parsed deterministically by the epic-orchestrator agent) and an
|
|
6
|
+
# optional SAFe-style intent block. The Markdown body below the frontmatter is the
|
|
7
|
+
# single human-authored narrative and is not machine-parsed.
|
|
8
|
+
#
|
|
9
|
+
# The DAG is keyed by stable `issue_num`. `feature_folder` is a resolvable hint
|
|
10
|
+
# that may point into docs/features/active/<folder> OR docs/features/completed/<folder>;
|
|
11
|
+
# it is not a stable identifier and changes when a child is promoted.
|
|
12
|
+
epic: <epic-slug>
|
|
13
|
+
integration_branch: epic/<epic-slug>-integration
|
|
14
|
+
created_at: <iso8601>
|
|
15
|
+
|
|
16
|
+
# Optional additive SAFe-style intent block. Omit the whole `intent` block when
|
|
17
|
+
# not used; when present, `epic_type` and `business_outcome_hypothesis` are
|
|
18
|
+
# required, and `leading_indicators` / `nfrs` are optional lists of strings.
|
|
19
|
+
intent:
|
|
20
|
+
epic_type: <business | enabler>
|
|
21
|
+
business_outcome_hypothesis: <the measurable outcome this epic is expected to move>
|
|
22
|
+
leading_indicators:
|
|
23
|
+
- <early signal that the hypothesis is being validated>
|
|
24
|
+
nfrs:
|
|
25
|
+
- <non-functional requirement the epic must satisfy>
|
|
26
|
+
|
|
27
|
+
# Manifest DAG. Primary key is `issue_num`. `depends_on` lists the `issue_num`
|
|
28
|
+
# values of upstream siblings (each must be another entry in `features[]`).
|
|
29
|
+
features:
|
|
30
|
+
- issue_num: <int>
|
|
31
|
+
feature_folder: <resolvable-hint-basename>
|
|
32
|
+
depends_on: []
|
|
33
|
+
- issue_num: <int>
|
|
34
|
+
feature_folder: <resolvable-hint-basename>
|
|
35
|
+
depends_on: [<upstream-issue_num>]
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
# <epic-name> - Epic
|
|
39
|
+
|
|
40
|
+
- Issue: #<tracking-issue>
|
|
41
|
+
- Owner: <name>
|
|
42
|
+
- Last Updated: YYYY-MM-DD
|
|
43
|
+
|
|
44
|
+
## Goal
|
|
45
|
+
|
|
46
|
+
State the epic objective and the measurable outcomes. Keep it user/impact
|
|
47
|
+
oriented, not implementation detail. This is the source from which the epic
|
|
48
|
+
GitHub issue body is generated.
|
|
49
|
+
|
|
50
|
+
## Scope
|
|
51
|
+
|
|
52
|
+
Enumerate what is in scope for this epic. Reference the child features by their
|
|
53
|
+
`issue_num` so the narrative and the manifest DAG stay aligned.
|
|
54
|
+
|
|
55
|
+
## Non-Goals
|
|
56
|
+
|
|
57
|
+
List what is explicitly out of scope so child features and reviewers do not
|
|
58
|
+
scope-creep into adjacent work.
|
|
59
|
+
|
|
60
|
+
## Shared Design
|
|
61
|
+
|
|
62
|
+
Capture the cross-cutting design decisions every child feature must honor:
|
|
63
|
+
|
|
64
|
+
- Shared behaviors/algorithms that must stay aligned across children.
|
|
65
|
+
- Determinism/performance/compatibility guarantees.
|
|
66
|
+
- Data/artifact locations, formats, or tooling expectations.
|
|
67
|
+
- Quality gates (tests/lint/type-checks) required across all children.
|
|
68
|
+
|
|
69
|
+
## Decomposition
|
|
70
|
+
|
|
71
|
+
Describe the child features and their ordering. Each child keeps its own git
|
|
72
|
+
branch/worktree and its own independent active/ -> completed/ lifecycle; this
|
|
73
|
+
section is the human-readable projection of the `features[]` DAG above.
|
|
74
|
+
|
|
75
|
+
- <Child feature A> (Issue #<id>) - wave 0
|
|
76
|
+
- <Child feature B> (Issue #<id>) - depends on #<id>
|
|
77
|
+
|
|
78
|
+
`epic-status.md` in this same directory is a generated projection of the epic
|
|
79
|
+
checkpoint; it is never the source of the DAG and is never hand-authored.
|
|
@@ -44,6 +44,10 @@
|
|
|
44
44
|
'.claude/hooks/enforce-pr-author-skill.ps1'
|
|
45
45
|
'.claude/hooks/validate-orchestrator-output.ps1'
|
|
46
46
|
'.claude/hooks/enforce-pr-author-skill.epic-base-branch.ps1'
|
|
47
|
+
# Issue #334 added this SessionStart hook that persists the current session id;
|
|
48
|
+
# measured here so the new production hook is not excluded from coverage. The
|
|
49
|
+
# test suite dot-sources the file (guarded body) so line attribution is valid.
|
|
50
|
+
'.claude/hooks/persist-session-id.ps1'
|
|
47
51
|
)
|
|
48
52
|
ExcludedPath = @(
|
|
49
53
|
'.claude/hooks/validate-feature-review-coverage.ps1' # Feature-review wrapper around repository evidence; not deterministic in normal unit-test execution.
|