oh-my-claude-sisyphus 3.8.15 → 3.9.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.mcp.json +1 -1
- package/README.md +9 -11
- package/agents/analyst.md +41 -0
- package/agents/architect.md +45 -0
- package/agents/critic.md +42 -0
- package/agents/deep-executor.md +193 -0
- package/agents/planner.md +82 -0
- package/bridge/mcp-server.cjs +1 -1
- package/commands/autopilot.md +2 -6
- package/commands/hud.md +7 -2
- package/commands/ralph.md +3 -3
- package/commands/ultrapilot.md +2 -6
- package/dist/__tests__/agent-registry.test.js +1 -1
- package/dist/__tests__/delegation-enforcement-levels.test.js +0 -1
- package/dist/__tests__/delegation-enforcement-levels.test.js.map +1 -1
- package/dist/__tests__/hooks/learner/parser.test.d.ts +5 -0
- package/dist/__tests__/hooks/learner/parser.test.d.ts.map +1 -0
- package/dist/__tests__/hooks/learner/parser.test.js +201 -0
- package/dist/__tests__/hooks/learner/parser.test.js.map +1 -0
- package/dist/__tests__/hud/cwd.test.d.ts +2 -0
- package/dist/__tests__/hud/cwd.test.d.ts.map +1 -0
- package/dist/__tests__/hud/cwd.test.js +62 -0
- package/dist/__tests__/hud/cwd.test.js.map +1 -0
- package/dist/__tests__/hud/defaults.test.d.ts +2 -0
- package/dist/__tests__/hud/defaults.test.d.ts.map +1 -0
- package/dist/__tests__/hud/defaults.test.js +21 -0
- package/dist/__tests__/hud/defaults.test.js.map +1 -0
- package/dist/__tests__/hud/render.test.d.ts +2 -0
- package/dist/__tests__/hud/render.test.d.ts.map +1 -0
- package/dist/__tests__/hud/render.test.js +141 -0
- package/dist/__tests__/hud/render.test.js.map +1 -0
- package/dist/__tests__/hud/thinking.test.d.ts +2 -0
- package/dist/__tests__/hud/thinking.test.d.ts.map +1 -0
- package/dist/__tests__/hud/thinking.test.js +32 -0
- package/dist/__tests__/hud/thinking.test.js.map +1 -0
- package/dist/__tests__/installer.test.js +8 -8
- package/dist/__tests__/installer.test.js.map +1 -1
- package/dist/__tests__/mnemosyne/parser.test.js +1 -1
- package/dist/__tests__/mnemosyne/parser.test.js.map +1 -1
- package/dist/__tests__/omc-tools-server.test.js +2 -2
- package/dist/__tests__/omc-tools-server.test.js.map +1 -1
- package/dist/__tests__/skills.test.js +5 -4
- package/dist/__tests__/skills.test.js.map +1 -1
- package/dist/agents/deep-executor.d.ts +15 -0
- package/dist/agents/deep-executor.d.ts.map +1 -0
- package/dist/agents/deep-executor.js +47 -0
- package/dist/agents/deep-executor.js.map +1 -0
- package/dist/agents/definitions.d.ts +15 -0
- package/dist/agents/definitions.d.ts.map +1 -1
- package/dist/agents/definitions.js +25 -0
- package/dist/agents/definitions.js.map +1 -1
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +1 -0
- package/dist/agents/index.js.map +1 -1
- package/dist/cli/commands/doctor-conflicts.d.ts +55 -0
- package/dist/cli/commands/doctor-conflicts.d.ts.map +1 -0
- package/dist/cli/commands/doctor-conflicts.js +261 -0
- package/dist/cli/commands/doctor-conflicts.js.map +1 -0
- package/dist/cli/index.js +16 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/features/auto-update.d.ts +12 -0
- package/dist/features/auto-update.d.ts.map +1 -1
- package/dist/features/auto-update.js +4 -1
- package/dist/features/auto-update.js.map +1 -1
- package/dist/features/context-injector/types.d.ts +1 -1
- package/dist/features/context-injector/types.d.ts.map +1 -1
- package/dist/features/continuation-enforcement.js +1 -1
- package/dist/features/state-manager/index.d.ts.map +1 -1
- package/dist/features/state-manager/index.js +7 -4
- package/dist/features/state-manager/index.js.map +1 -1
- package/dist/features/verification/example.d.ts.map +1 -1
- package/dist/features/verification/example.js +4 -2
- package/dist/features/verification/example.js.map +1 -1
- package/dist/hooks/__tests__/bridge.test.d.ts +2 -0
- package/dist/hooks/__tests__/bridge.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/bridge.test.js +199 -0
- package/dist/hooks/__tests__/bridge.test.js.map +1 -0
- package/dist/hooks/beads-context/__tests__/index.test.d.ts +2 -0
- package/dist/hooks/beads-context/__tests__/index.test.d.ts.map +1 -0
- package/dist/hooks/beads-context/__tests__/index.test.js +150 -0
- package/dist/hooks/beads-context/__tests__/index.test.js.map +1 -0
- package/dist/hooks/beads-context/constants.d.ts +3 -0
- package/dist/hooks/beads-context/constants.d.ts.map +1 -0
- package/dist/hooks/beads-context/constants.js +35 -0
- package/dist/hooks/beads-context/constants.js.map +1 -0
- package/dist/hooks/beads-context/index.d.ts +21 -0
- package/dist/hooks/beads-context/index.d.ts.map +1 -0
- package/dist/hooks/beads-context/index.js +62 -0
- package/dist/hooks/beads-context/index.js.map +1 -0
- package/dist/hooks/beads-context/types.d.ts +7 -0
- package/dist/hooks/beads-context/types.d.ts.map +1 -0
- package/dist/hooks/beads-context/types.js +2 -0
- package/dist/hooks/beads-context/types.js.map +1 -0
- package/dist/hooks/bridge.d.ts +4 -0
- package/dist/hooks/bridge.d.ts.map +1 -1
- package/dist/hooks/bridge.js +80 -47
- package/dist/hooks/bridge.js.map +1 -1
- package/dist/hooks/index.d.ts +2 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +4 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/learner/parser.d.ts.map +1 -1
- package/dist/hooks/learner/parser.js +12 -5
- package/dist/hooks/learner/parser.js.map +1 -1
- package/dist/hooks/mode-registry/index.d.ts +2 -0
- package/dist/hooks/mode-registry/index.d.ts.map +1 -1
- package/dist/hooks/mode-registry/index.js +8 -19
- package/dist/hooks/mode-registry/index.js.map +1 -1
- package/dist/hooks/permission-handler/index.d.ts.map +1 -1
- package/dist/hooks/permission-handler/index.js +3 -1
- package/dist/hooks/permission-handler/index.js.map +1 -1
- package/dist/hooks/persistent-mode/index.d.ts +1 -1
- package/dist/hooks/persistent-mode/index.d.ts.map +1 -1
- package/dist/hooks/persistent-mode/index.js +5 -33
- package/dist/hooks/persistent-mode/index.js.map +1 -1
- package/dist/hooks/ralph/index.d.ts +1 -1
- package/dist/hooks/ralph/index.d.ts.map +1 -1
- package/dist/hooks/ralph/index.js +1 -1
- package/dist/hooks/ralph/index.js.map +1 -1
- package/dist/hooks/ralph/loop.d.ts +1 -9
- package/dist/hooks/ralph/loop.d.ts.map +1 -1
- package/dist/hooks/ralph/loop.js +1 -37
- package/dist/hooks/ralph/loop.js.map +1 -1
- package/dist/hooks/ralph/prd.js +1 -1
- package/dist/hooks/ralph/verifier.d.ts +4 -5
- package/dist/hooks/ralph/verifier.d.ts.map +1 -1
- package/dist/hooks/ralph/verifier.js +7 -10
- package/dist/hooks/ralph/verifier.js.map +1 -1
- package/dist/hooks/session-end/index.d.ts +13 -0
- package/dist/hooks/session-end/index.d.ts.map +1 -1
- package/dist/hooks/session-end/index.js +69 -0
- package/dist/hooks/session-end/index.js.map +1 -1
- package/dist/hooks/setup/index.d.ts.map +1 -1
- package/dist/hooks/setup/index.js +12 -5
- package/dist/hooks/setup/index.js.map +1 -1
- package/dist/hooks/subagent-tracker/index.d.ts.map +1 -1
- package/dist/hooks/subagent-tracker/index.js +25 -9
- package/dist/hooks/subagent-tracker/index.js.map +1 -1
- package/dist/hooks/ultrawork/index.d.ts +2 -2
- package/dist/hooks/ultrawork/index.d.ts.map +1 -1
- package/dist/hooks/ultrawork/index.js +2 -46
- package/dist/hooks/ultrawork/index.js.map +1 -1
- package/dist/hud/elements/cwd.d.ts +15 -0
- package/dist/hud/elements/cwd.d.ts.map +1 -0
- package/dist/hud/elements/cwd.js +39 -0
- package/dist/hud/elements/cwd.js.map +1 -0
- package/dist/hud/elements/index.d.ts +1 -0
- package/dist/hud/elements/index.d.ts.map +1 -1
- package/dist/hud/elements/index.js +1 -0
- package/dist/hud/elements/index.js.map +1 -1
- package/dist/hud/elements/thinking.d.ts +7 -5
- package/dist/hud/elements/thinking.d.ts.map +1 -1
- package/dist/hud/elements/thinking.js +18 -6
- package/dist/hud/elements/thinking.js.map +1 -1
- package/dist/hud/index.js +5 -3
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/omc-state.d.ts +1 -1
- package/dist/hud/omc-state.d.ts.map +1 -1
- package/dist/hud/omc-state.js +14 -31
- package/dist/hud/omc-state.js.map +1 -1
- package/dist/hud/render.d.ts +9 -0
- package/dist/hud/render.d.ts.map +1 -1
- package/dist/hud/render.js +27 -7
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/state.d.ts +2 -2
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +4 -33
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/transcript.d.ts +4 -1
- package/dist/hud/transcript.d.ts.map +1 -1
- package/dist/hud/transcript.js +4 -9
- package/dist/hud/transcript.js.map +1 -1
- package/dist/hud/types.d.ts +20 -1
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/hud/types.js +38 -9
- package/dist/hud/types.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/installer/__tests__/claude-md-merge.test.d.ts +6 -0
- package/dist/installer/__tests__/claude-md-merge.test.d.ts.map +1 -0
- package/dist/installer/__tests__/claude-md-merge.test.js +220 -0
- package/dist/installer/__tests__/claude-md-merge.test.js.map +1 -0
- package/dist/installer/__tests__/safe-installer.test.d.ts +6 -0
- package/dist/installer/__tests__/safe-installer.test.d.ts.map +1 -0
- package/dist/installer/__tests__/safe-installer.test.js +172 -0
- package/dist/installer/__tests__/safe-installer.test.js.map +1 -0
- package/dist/installer/hooks.d.ts +1 -1
- package/dist/installer/hooks.d.ts.map +1 -1
- package/dist/installer/hooks.js +4 -2
- package/dist/installer/hooks.js.map +1 -1
- package/dist/installer/index.d.ts +27 -1
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +209 -85
- package/dist/installer/index.js.map +1 -1
- package/dist/mcp/omc-tools-server.d.ts +1 -1
- package/dist/mcp/omc-tools-server.d.ts.map +1 -1
- package/dist/mcp/omc-tools-server.js +3 -3
- package/dist/mcp/omc-tools-server.js.map +1 -1
- package/dist/mcp/standalone-server.js +1 -1
- package/dist/mcp/standalone-server.js.map +1 -1
- package/dist/verification/tier-selector.d.ts +40 -0
- package/dist/verification/tier-selector.d.ts.map +1 -0
- package/dist/verification/tier-selector.js +95 -0
- package/dist/verification/tier-selector.js.map +1 -0
- package/dist/verification/tier-selector.test.d.ts +2 -0
- package/dist/verification/tier-selector.test.d.ts.map +1 -0
- package/dist/verification/tier-selector.test.js +282 -0
- package/dist/verification/tier-selector.test.js.map +1 -0
- package/docs/AGENTS.md +100 -0
- package/docs/ARCHITECTURE.md +11 -7
- package/docs/CLAUDE.md +89 -379
- package/docs/DELEGATION-ENFORCER.md +1 -2
- package/docs/MIGRATION.md +1 -1
- package/docs/REFERENCE.md +29 -9
- package/docs/SYNC-SYSTEM.md +0 -2
- package/docs/partials/agent-tiers.md +165 -0
- package/docs/partials/features.md +131 -0
- package/docs/partials/mode-hierarchy.md +120 -0
- package/docs/partials/mode-selection-guide.md +82 -0
- package/docs/partials/verification-tiers.md +107 -0
- package/docs/shared/agent-tiers.md +165 -0
- package/docs/shared/features.md +131 -0
- package/docs/shared/mode-hierarchy.md +120 -0
- package/docs/shared/mode-selection-guide.md +82 -0
- package/docs/shared/verification-tiers.md +107 -0
- package/package.json +4 -3
- package/scripts/compose-docs.mjs +44 -0
- package/scripts/keyword-detector.mjs +13 -3
- package/scripts/persistent-mode.mjs +78 -47
- package/scripts/test-mutual-exclusion.ts +3 -3
- package/skills/AGENTS.md +59 -44
- package/skills/autopilot/SKILL.md +0 -2
- package/skills/cancel/SKILL.md +13 -32
- package/skills/deep-executor/SKILL.md +50 -0
- package/skills/ecomode/SKILL.md +58 -104
- package/skills/hud/SKILL.md +3 -2
- package/skills/omc-setup/SKILL.md +197 -20
- package/skills/plan/SKILL.md +62 -0
- package/skills/project-session-manager/SKILL.md +87 -4
- package/skills/project-session-manager/lib/config.sh +54 -5
- package/skills/project-session-manager/lib/parse.sh +65 -11
- package/skills/project-session-manager/lib/providers/github.sh +52 -0
- package/skills/project-session-manager/lib/providers/interface.sh +76 -0
- package/skills/project-session-manager/lib/providers/jira.sh +79 -0
- package/skills/project-session-manager/lib/session.sh +49 -12
- package/skills/project-session-manager/lib/worktree.sh +37 -4
- package/skills/project-session-manager/psm.sh +116 -51
- package/skills/ralph/SKILL.md +48 -44
- package/skills/ultrawork/SKILL.md +56 -67
- package/templates/hooks/keyword-detector.mjs +21 -13
- package/templates/hooks/lib/stdin.mjs +62 -0
- package/templates/hooks/persistent-mode.mjs +75 -34
- package/templates/hooks/post-tool-use.mjs +8 -10
- package/templates/hooks/pre-tool-use.mjs +9 -6
- package/templates/hooks/session-start.mjs +7 -8
- package/agents/AGENTS.md +0 -144
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PSM GitHub Provider
|
|
3
|
+
|
|
4
|
+
provider_github_available() {
|
|
5
|
+
command -v gh &> /dev/null
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
provider_github_detect_ref() {
|
|
9
|
+
local ref="$1"
|
|
10
|
+
# Matches github URLs or owner/repo#num patterns
|
|
11
|
+
[[ "$ref" =~ ^https://github\.com/ ]] || [[ "$ref" =~ ^[a-zA-Z0-9_-]+/[a-zA-Z0-9_.-]+#[0-9]+$ ]]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
provider_github_fetch_pr() {
|
|
15
|
+
local pr_number="$1"
|
|
16
|
+
local repo="$2"
|
|
17
|
+
gh pr view "$pr_number" --repo "$repo" --json number,title,author,headRefName,baseRefName,body,url 2>/dev/null
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
provider_github_fetch_issue() {
|
|
21
|
+
local issue_number="$1"
|
|
22
|
+
local repo="$2"
|
|
23
|
+
gh issue view "$issue_number" --repo "$repo" --json number,title,body,labels,url 2>/dev/null
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
provider_github_pr_merged() {
|
|
27
|
+
local pr_number="$1"
|
|
28
|
+
local repo="$2"
|
|
29
|
+
local merged
|
|
30
|
+
merged=$(gh pr view "$pr_number" --repo "$repo" --json merged 2>/dev/null | jq -r '.merged')
|
|
31
|
+
[[ "$merged" == "true" ]]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
provider_github_issue_closed() {
|
|
35
|
+
local issue_number="$1"
|
|
36
|
+
local repo="$2"
|
|
37
|
+
local closed
|
|
38
|
+
closed=$(gh issue view "$issue_number" --repo "$repo" --json closed 2>/dev/null | jq -r '.closed')
|
|
39
|
+
[[ "$closed" == "true" ]]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
provider_github_clone_url() {
|
|
43
|
+
local repo="$1"
|
|
44
|
+
|
|
45
|
+
# Validate owner/repo format
|
|
46
|
+
if [[ ! "$repo" =~ ^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$ ]]; then
|
|
47
|
+
echo "error|Invalid repository format: $repo" >&2
|
|
48
|
+
return 1
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
echo "https://github.com/${repo}.git"
|
|
52
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PSM Provider Interface
|
|
3
|
+
# Each provider implements: _available, _detect_ref, _fetch_issue, _issue_closed,
|
|
4
|
+
# _fetch_pr (optional), _pr_merged (optional), _clone_url
|
|
5
|
+
|
|
6
|
+
# List available providers
|
|
7
|
+
provider_list() {
|
|
8
|
+
echo "github jira"
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
# Allowlist of valid providers
|
|
12
|
+
readonly VALID_PROVIDERS="github jira"
|
|
13
|
+
|
|
14
|
+
# Check if a provider is available (CLI installed)
|
|
15
|
+
# Usage: provider_available "github"
|
|
16
|
+
provider_available() {
|
|
17
|
+
local provider="$1"
|
|
18
|
+
|
|
19
|
+
# Validate provider against allowlist
|
|
20
|
+
if ! echo "$VALID_PROVIDERS" | grep -qw "$provider"; then
|
|
21
|
+
echo "error|Invalid provider: $provider" >&2
|
|
22
|
+
return 1
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
"provider_${provider}_available"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
# Dispatch to provider function
|
|
29
|
+
# Usage: provider_call "github" "fetch_issue" "123" "owner/repo"
|
|
30
|
+
provider_call() {
|
|
31
|
+
local provider="$1"
|
|
32
|
+
local func="$2"
|
|
33
|
+
shift 2
|
|
34
|
+
|
|
35
|
+
# Validate provider against allowlist
|
|
36
|
+
if ! echo "$VALID_PROVIDERS" | grep -qw "$provider"; then
|
|
37
|
+
echo "error|Invalid provider: $provider" >&2
|
|
38
|
+
return 1
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Validate function name (alphanumeric and underscore only)
|
|
42
|
+
if [[ ! "$func" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then
|
|
43
|
+
echo "error|Invalid function name: $func" >&2
|
|
44
|
+
return 1
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
"provider_${provider}_${func}" "$@"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Detect provider from reference (with config validation)
|
|
51
|
+
# Usage: provider_detect_from_ref "PROJ-123"
|
|
52
|
+
# Returns: provider name or empty
|
|
53
|
+
provider_detect_from_ref() {
|
|
54
|
+
local ref="$1"
|
|
55
|
+
|
|
56
|
+
# Check Jira pattern first (config-validated)
|
|
57
|
+
if psm_detect_jira_key "$ref" >/dev/null 2>&1; then
|
|
58
|
+
echo "jira"
|
|
59
|
+
return 0
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# GitHub URL patterns
|
|
63
|
+
if [[ "$ref" =~ ^https://github\.com/ ]]; then
|
|
64
|
+
echo "github"
|
|
65
|
+
return 0
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# owner/repo#num pattern -> GitHub
|
|
69
|
+
if [[ "$ref" =~ ^[a-zA-Z0-9_-]+/[a-zA-Z0-9_.-]+#[0-9]+$ ]]; then
|
|
70
|
+
echo "github"
|
|
71
|
+
return 0
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
# Default
|
|
75
|
+
echo "github"
|
|
76
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PSM Jira Provider
|
|
3
|
+
# Uses `jira` CLI (https://github.com/ankitpokhrel/jira-cli)
|
|
4
|
+
|
|
5
|
+
provider_jira_available() {
|
|
6
|
+
command -v jira &> /dev/null
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
provider_jira_detect_ref() {
|
|
10
|
+
local ref="$1"
|
|
11
|
+
# Config-validated detection only
|
|
12
|
+
psm_detect_jira_key "$ref" >/dev/null 2>&1
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
provider_jira_fetch_issue() {
|
|
16
|
+
local issue_key="$1" # e.g., "PROJ-123"
|
|
17
|
+
# Note: second arg (repo) is ignored for Jira
|
|
18
|
+
jira issue view "$issue_key" --output json 2>/dev/null
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
provider_jira_issue_closed() {
|
|
22
|
+
local issue_key="$1"
|
|
23
|
+
local status_category
|
|
24
|
+
status_category=$(jira issue view "$issue_key" --output json 2>/dev/null | jq -r '.fields.status.statusCategory.key')
|
|
25
|
+
# Jira status categories: "new", "indeterminate", "done"
|
|
26
|
+
[[ "$status_category" == "done" ]]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# Jira has no PRs - return error
|
|
30
|
+
provider_jira_fetch_pr() {
|
|
31
|
+
echo '{"error": "Jira does not support pull requests"}' >&2
|
|
32
|
+
return 1
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
provider_jira_pr_merged() {
|
|
36
|
+
return 1 # Always false - Jira has no PRs
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
provider_jira_clone_url() {
|
|
40
|
+
local alias="$1"
|
|
41
|
+
# For Jira, we need to get clone_url from config
|
|
42
|
+
# First try explicit clone_url, then fall back to repo as GitHub
|
|
43
|
+
local clone_url
|
|
44
|
+
clone_url=$(psm_get_project_clone_url "$alias")
|
|
45
|
+
if [[ -n "$clone_url" ]]; then
|
|
46
|
+
echo "$clone_url"
|
|
47
|
+
return 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
local repo
|
|
51
|
+
repo=$(psm_get_project_repo "$alias")
|
|
52
|
+
if [[ -n "$repo" ]]; then
|
|
53
|
+
echo "https://github.com/${repo}.git"
|
|
54
|
+
return 0
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
echo "error: No clone_url or repo configured for alias '$alias'" >&2
|
|
58
|
+
return 1
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# Parse Jira reference into components
|
|
62
|
+
# Input: "PROJ-123" or "mywork#123"
|
|
63
|
+
# Output: Extended format for session creation
|
|
64
|
+
provider_jira_parse_ref() {
|
|
65
|
+
local ref="$1"
|
|
66
|
+
local jira_info
|
|
67
|
+
|
|
68
|
+
# Try direct PROJ-123 pattern
|
|
69
|
+
if jira_info=$(psm_detect_jira_key "$ref"); then
|
|
70
|
+
IFS='|' read -r alias project_key issue_number <<< "$jira_info"
|
|
71
|
+
local project_info
|
|
72
|
+
project_info=$(psm_get_project "$alias")
|
|
73
|
+
IFS='|' read -r repo local_path base <<< "$project_info"
|
|
74
|
+
echo "issue|${alias}|${repo}|${issue_number}|${local_path}|${base}|jira|${project_key}-${issue_number}"
|
|
75
|
+
return 0
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
return 1
|
|
79
|
+
}
|
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# PSM Session Registry Management
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
# Lock file for atomic registry operations
|
|
5
|
+
PSM_LOCK_FILE="${PSM_DATA_DIR:-.psm}/.psm-lock"
|
|
6
|
+
|
|
7
|
+
# Wrapper for atomic operations with file locking
|
|
8
|
+
# Usage: psm_with_lock <command> [args...]
|
|
9
|
+
psm_with_lock() {
|
|
10
|
+
local timeout="${PSM_LOCK_TIMEOUT:-5}"
|
|
11
|
+
(
|
|
12
|
+
flock -w "$timeout" 200 || {
|
|
13
|
+
echo "error|Failed to acquire lock after ${timeout}s" >&2
|
|
14
|
+
return 1
|
|
15
|
+
}
|
|
16
|
+
"$@"
|
|
17
|
+
) 200>"$PSM_LOCK_FILE"
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
# Internal: Add session to registry (must be called via psm_with_lock)
|
|
21
|
+
_psm_add_session_impl() {
|
|
7
22
|
local id="$1"
|
|
8
23
|
local type="$2"
|
|
9
24
|
local project="$3"
|
|
@@ -14,6 +29,8 @@ psm_add_session() {
|
|
|
14
29
|
local worktree="$8"
|
|
15
30
|
local source_repo="$9"
|
|
16
31
|
local metadata="${10:-{}}"
|
|
32
|
+
local provider="${11:-github}"
|
|
33
|
+
local provider_ref="${12:-}"
|
|
17
34
|
|
|
18
35
|
local now=$(date -Iseconds)
|
|
19
36
|
|
|
@@ -28,6 +45,8 @@ psm_add_session() {
|
|
|
28
45
|
--arg worktree "$worktree" \
|
|
29
46
|
--arg source "$source_repo" \
|
|
30
47
|
--arg now "$now" \
|
|
48
|
+
--arg provider "$provider" \
|
|
49
|
+
--arg provider_ref "$provider_ref" \
|
|
31
50
|
--argjson meta "$metadata" \
|
|
32
51
|
'.sessions[$id] = {
|
|
33
52
|
"id": $id,
|
|
@@ -42,21 +61,28 @@ psm_add_session() {
|
|
|
42
61
|
"created_at": $now,
|
|
43
62
|
"last_accessed": $now,
|
|
44
63
|
"state": "active",
|
|
64
|
+
"provider": $provider,
|
|
65
|
+
"provider_ref": $provider_ref,
|
|
45
66
|
"metadata": $meta
|
|
46
67
|
} | .stats.total_created += 1' \
|
|
47
68
|
"$PSM_SESSIONS" > "$tmp" && mv "$tmp" "$PSM_SESSIONS"
|
|
48
69
|
}
|
|
49
70
|
|
|
71
|
+
# Add session to registry (with file locking)
|
|
72
|
+
# Usage: psm_add_session <id> <type> <project> <ref> <branch> <base> <tmux> <worktree> <source_repo> <metadata_json> [provider] [provider_ref]
|
|
73
|
+
psm_add_session() {
|
|
74
|
+
psm_with_lock _psm_add_session_impl "$@"
|
|
75
|
+
}
|
|
76
|
+
|
|
50
77
|
# Get session by ID
|
|
51
78
|
# Usage: psm_get_session <id>
|
|
52
79
|
psm_get_session() {
|
|
53
80
|
local id="$1"
|
|
54
|
-
jq -r ".sessions[
|
|
81
|
+
jq -r --arg i "$id" '.sessions[$i] // empty' "$PSM_SESSIONS"
|
|
55
82
|
}
|
|
56
83
|
|
|
57
|
-
# Update session state
|
|
58
|
-
|
|
59
|
-
psm_update_session_state() {
|
|
84
|
+
# Internal: Update session state (must be called via psm_with_lock)
|
|
85
|
+
_psm_update_session_state_impl() {
|
|
60
86
|
local id="$1"
|
|
61
87
|
local state="$2"
|
|
62
88
|
local now=$(date -Iseconds)
|
|
@@ -69,9 +95,14 @@ psm_update_session_state() {
|
|
|
69
95
|
"$PSM_SESSIONS" > "$tmp" && mv "$tmp" "$PSM_SESSIONS"
|
|
70
96
|
}
|
|
71
97
|
|
|
72
|
-
#
|
|
73
|
-
# Usage:
|
|
74
|
-
|
|
98
|
+
# Update session state (with file locking)
|
|
99
|
+
# Usage: psm_update_session_state <id> <state>
|
|
100
|
+
psm_update_session_state() {
|
|
101
|
+
psm_with_lock _psm_update_session_state_impl "$@"
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# Internal: Remove session from registry (must be called via psm_with_lock)
|
|
105
|
+
_psm_remove_session_impl() {
|
|
75
106
|
local id="$1"
|
|
76
107
|
|
|
77
108
|
local tmp=$(mktemp)
|
|
@@ -80,13 +111,19 @@ psm_remove_session() {
|
|
|
80
111
|
"$PSM_SESSIONS" > "$tmp" && mv "$tmp" "$PSM_SESSIONS"
|
|
81
112
|
}
|
|
82
113
|
|
|
114
|
+
# Remove session from registry (with file locking)
|
|
115
|
+
# Usage: psm_remove_session <id>
|
|
116
|
+
psm_remove_session() {
|
|
117
|
+
psm_with_lock _psm_remove_session_impl "$@"
|
|
118
|
+
}
|
|
119
|
+
|
|
83
120
|
# List all sessions
|
|
84
121
|
# Usage: psm_list_sessions [project]
|
|
85
122
|
psm_list_sessions() {
|
|
86
123
|
local project="$1"
|
|
87
124
|
|
|
88
125
|
if [[ -n "$project" ]]; then
|
|
89
|
-
jq -r ".sessions | to_entries[] | select(.value.project ==
|
|
126
|
+
jq -r --arg p "$project" '.sessions | to_entries[] | select(.value.project == $p) | .value | "\(.id)|\(.type)|\(.state)|\(.worktree)"' "$PSM_SESSIONS"
|
|
90
127
|
else
|
|
91
128
|
jq -r '.sessions | to_entries[] | .value | "\(.id)|\(.type)|\(.state)|\(.worktree)"' "$PSM_SESSIONS"
|
|
92
129
|
fi
|
|
@@ -95,7 +132,7 @@ psm_list_sessions() {
|
|
|
95
132
|
# Get sessions by state
|
|
96
133
|
psm_get_sessions_by_state() {
|
|
97
134
|
local state="$1"
|
|
98
|
-
jq -r ".sessions | to_entries[] | select(.value.state ==
|
|
135
|
+
jq -r --arg s "$state" '.sessions | to_entries[] | select(.value.state == $s) | .value.id' "$PSM_SESSIONS"
|
|
99
136
|
}
|
|
100
137
|
|
|
101
138
|
# Get session count
|
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# PSM Worktree Management
|
|
3
3
|
|
|
4
|
+
# Validate worktree path is under PSM worktree root before deletion
|
|
5
|
+
# Returns 0 if valid, 1 if invalid
|
|
6
|
+
# Usage: validate_worktree_path <path>
|
|
7
|
+
validate_worktree_path() {
|
|
8
|
+
local path="$1"
|
|
9
|
+
local worktree_root
|
|
10
|
+
worktree_root=$(psm_get_worktree_root 2>/dev/null) || return 1
|
|
11
|
+
|
|
12
|
+
# Path must exist and be a directory
|
|
13
|
+
if [[ ! -d "$path" ]]; then
|
|
14
|
+
return 1
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# Resolve to absolute paths for comparison
|
|
18
|
+
local abs_path abs_root
|
|
19
|
+
abs_path=$(cd "$path" 2>/dev/null && pwd) || return 1
|
|
20
|
+
abs_root=$(cd "$worktree_root" 2>/dev/null && pwd) || return 1
|
|
21
|
+
|
|
22
|
+
# Check path is under root and doesn't contain ..
|
|
23
|
+
if [[ "$abs_path" != "$abs_root"/* ]] || [[ "$path" == *".."* ]]; then
|
|
24
|
+
echo "error|Invalid worktree path: not under PSM root" >&2
|
|
25
|
+
return 1
|
|
26
|
+
fi
|
|
27
|
+
return 0
|
|
28
|
+
}
|
|
29
|
+
|
|
4
30
|
# Create a worktree for PR review
|
|
5
31
|
# Usage: psm_create_pr_worktree <local_repo> <alias> <pr_number> <pr_branch>
|
|
6
32
|
psm_create_pr_worktree() {
|
|
@@ -146,10 +172,17 @@ psm_remove_worktree() {
|
|
|
146
172
|
fi
|
|
147
173
|
|
|
148
174
|
cd "$local_repo" || return 1
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
175
|
+
|
|
176
|
+
# Validate path is under PSM worktree root before any deletion
|
|
177
|
+
if validate_worktree_path "$worktree_path"; then
|
|
178
|
+
git worktree remove "$worktree_path" --force 2>/dev/null || {
|
|
179
|
+
# Force remove the directory if git worktree remove fails
|
|
180
|
+
rm -rf "$worktree_path"
|
|
181
|
+
}
|
|
182
|
+
else
|
|
183
|
+
echo "error|Refusing to delete path outside worktree root: $worktree_path" >&2
|
|
184
|
+
return 1
|
|
185
|
+
fi
|
|
153
186
|
|
|
154
187
|
echo "removed|$worktree_path"
|
|
155
188
|
return 0
|
|
@@ -13,6 +13,11 @@ source "$SCRIPT_DIR/lib/worktree.sh"
|
|
|
13
13
|
source "$SCRIPT_DIR/lib/tmux.sh"
|
|
14
14
|
source "$SCRIPT_DIR/lib/session.sh"
|
|
15
15
|
|
|
16
|
+
# Source provider files
|
|
17
|
+
source "$SCRIPT_DIR/lib/providers/interface.sh"
|
|
18
|
+
source "$SCRIPT_DIR/lib/providers/github.sh"
|
|
19
|
+
source "$SCRIPT_DIR/lib/providers/jira.sh"
|
|
20
|
+
|
|
16
21
|
# Colors for output
|
|
17
22
|
RED='\033[0;31m'
|
|
18
23
|
GREEN='\033[0;32m'
|
|
@@ -38,15 +43,14 @@ check_dependencies() {
|
|
|
38
43
|
missing+=("jq")
|
|
39
44
|
fi
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
fi
|
|
46
|
+
# Note: gh and jira are checked per-operation, not globally
|
|
47
|
+
# This allows users without gh to still use Jira, and vice versa
|
|
44
48
|
|
|
45
49
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
|
46
50
|
log_error "Missing required dependencies: ${missing[*]}"
|
|
47
51
|
log_info "Install with:"
|
|
48
|
-
log_info " Ubuntu/Debian: sudo apt install git jq
|
|
49
|
-
log_info " macOS: brew install git jq
|
|
52
|
+
log_info " Ubuntu/Debian: sudo apt install git jq"
|
|
53
|
+
log_info " macOS: brew install git jq"
|
|
50
54
|
exit 1
|
|
51
55
|
fi
|
|
52
56
|
|
|
@@ -106,7 +110,21 @@ cmd_review() {
|
|
|
106
110
|
return 1
|
|
107
111
|
fi
|
|
108
112
|
|
|
109
|
-
IFS='|' read -r type alias repo pr_number local_path base <<< "$parsed"
|
|
113
|
+
IFS='|' read -r type alias repo pr_number local_path base provider provider_ref <<< "$parsed"
|
|
114
|
+
|
|
115
|
+
# Provider guard: Jira doesn't have PRs
|
|
116
|
+
if [[ "$provider" == "jira" ]]; then
|
|
117
|
+
log_error "Jira issues cannot be 'reviewed' - Jira has no PR concept."
|
|
118
|
+
log_info "Use 'psm fix $ref' to work on a Jira issue instead."
|
|
119
|
+
log_info "Jira integration supports: fix, feature"
|
|
120
|
+
return 1
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
# Check GitHub CLI availability
|
|
124
|
+
if ! provider_github_available; then
|
|
125
|
+
log_error "GitHub CLI (gh) not found. Install: brew install gh"
|
|
126
|
+
return 1
|
|
127
|
+
fi
|
|
110
128
|
|
|
111
129
|
if [[ -z "$repo" ]]; then
|
|
112
130
|
log_error "Could not determine repository"
|
|
@@ -117,7 +135,7 @@ cmd_review() {
|
|
|
117
135
|
|
|
118
136
|
# Fetch PR info
|
|
119
137
|
local pr_info
|
|
120
|
-
pr_info=$(
|
|
138
|
+
pr_info=$(provider_call "github" fetch_pr "$pr_number" "$repo") || {
|
|
121
139
|
log_error "Failed to fetch PR #${pr_number}. Check if the PR exists and you have access."
|
|
122
140
|
return 1
|
|
123
141
|
}
|
|
@@ -143,7 +161,9 @@ cmd_review() {
|
|
|
143
161
|
local_path="${HOME}/Workspace/$(basename "$repo")"
|
|
144
162
|
if [[ ! -d "$local_path" ]]; then
|
|
145
163
|
log_info "Cloning repository to $local_path..."
|
|
146
|
-
|
|
164
|
+
local clone_url
|
|
165
|
+
clone_url=$(provider_call "github" clone_url "$repo")
|
|
166
|
+
git clone "$clone_url" "$local_path" || {
|
|
147
167
|
log_error "Failed to clone repository"
|
|
148
168
|
return 1
|
|
149
169
|
}
|
|
@@ -198,18 +218,16 @@ cmd_review() {
|
|
|
198
218
|
fi
|
|
199
219
|
|
|
200
220
|
# Create session metadata
|
|
201
|
-
local metadata
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
EOF
|
|
209
|
-
)
|
|
221
|
+
local metadata
|
|
222
|
+
metadata=$(jq -n \
|
|
223
|
+
--argjson pr_number "$pr_number" \
|
|
224
|
+
--arg pr_title "$pr_title" \
|
|
225
|
+
--arg pr_author "$pr_author" \
|
|
226
|
+
--arg pr_url "$pr_url" \
|
|
227
|
+
'{pr_number: $pr_number, pr_title: $pr_title, pr_author: $pr_author, pr_url: $pr_url}')
|
|
210
228
|
|
|
211
229
|
# Add to registry
|
|
212
|
-
psm_add_session "$session_id" "review" "$alias" "pr-${pr_number}" "$head_branch" "$base_branch" "$session_name" "$worktree_path" "$local_path" "$metadata"
|
|
230
|
+
psm_add_session "$session_id" "review" "$alias" "pr-${pr_number}" "$head_branch" "$base_branch" "$session_name" "$worktree_path" "$local_path" "$metadata" "github" "${repo}#${pr_number}"
|
|
213
231
|
|
|
214
232
|
# Output summary
|
|
215
233
|
echo ""
|
|
@@ -242,24 +260,45 @@ cmd_fix() {
|
|
|
242
260
|
return 1
|
|
243
261
|
fi
|
|
244
262
|
|
|
245
|
-
IFS='|' read -r type alias repo issue_number local_path base <<< "$parsed"
|
|
263
|
+
IFS='|' read -r type alias repo issue_number local_path base provider provider_ref <<< "$parsed"
|
|
246
264
|
|
|
247
|
-
|
|
265
|
+
# Check provider CLI availability
|
|
266
|
+
if [[ "$provider" == "jira" ]]; then
|
|
267
|
+
if ! provider_jira_available; then
|
|
268
|
+
log_error "Jira CLI not found. Install: brew install ankitpokhrel/jira-cli/jira-cli"
|
|
269
|
+
return 1
|
|
270
|
+
fi
|
|
271
|
+
else
|
|
272
|
+
if ! provider_github_available; then
|
|
273
|
+
log_error "GitHub CLI (gh) not found. Install: brew install gh"
|
|
274
|
+
return 1
|
|
275
|
+
fi
|
|
276
|
+
fi
|
|
277
|
+
|
|
278
|
+
if [[ -z "$repo" && "$provider" != "jira" ]]; then
|
|
248
279
|
log_error "Could not determine repository"
|
|
249
280
|
return 1
|
|
250
281
|
fi
|
|
251
282
|
|
|
252
|
-
log_info "Fetching issue #${issue_number}
|
|
283
|
+
log_info "Fetching issue #${issue_number}..."
|
|
253
284
|
|
|
254
285
|
# Fetch issue info
|
|
255
286
|
local issue_info
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
287
|
+
if [[ "$provider" == "jira" ]]; then
|
|
288
|
+
issue_info=$(provider_call "jira" fetch_issue "$provider_ref") || {
|
|
289
|
+
log_error "Failed to fetch Jira issue ${provider_ref}"
|
|
290
|
+
return 1
|
|
291
|
+
}
|
|
292
|
+
local issue_title=$(echo "$issue_info" | jq -r '.fields.summary')
|
|
293
|
+
local issue_url=$(echo "$issue_info" | jq -r '.self // empty')
|
|
294
|
+
else
|
|
295
|
+
issue_info=$(provider_call "github" fetch_issue "$issue_number" "$repo") || {
|
|
296
|
+
log_error "Failed to fetch issue #${issue_number}"
|
|
297
|
+
return 1
|
|
298
|
+
}
|
|
299
|
+
local issue_title=$(echo "$issue_info" | jq -r '.title')
|
|
300
|
+
local issue_url=$(echo "$issue_info" | jq -r '.url')
|
|
301
|
+
fi
|
|
263
302
|
local slug=$(psm_slugify "$issue_title" 20)
|
|
264
303
|
|
|
265
304
|
log_info "Issue: #${issue_number} - ${issue_title}"
|
|
@@ -271,10 +310,19 @@ cmd_fix() {
|
|
|
271
310
|
|
|
272
311
|
# Determine local path
|
|
273
312
|
if [[ -z "$local_path" || ! -d "$local_path" ]]; then
|
|
274
|
-
local_path="${HOME}/Workspace/$(basename "$repo")"
|
|
313
|
+
local_path="${HOME}/Workspace/$(basename "${repo:-$alias}")"
|
|
275
314
|
if [[ ! -d "$local_path" ]]; then
|
|
276
315
|
log_info "Cloning repository..."
|
|
277
|
-
|
|
316
|
+
local clone_url
|
|
317
|
+
if [[ "$provider" == "jira" ]]; then
|
|
318
|
+
clone_url=$(provider_call "jira" clone_url "$alias") || {
|
|
319
|
+
log_error "Failed to get clone URL for '$alias'. Configure 'repo' or 'clone_url' in projects.json"
|
|
320
|
+
return 1
|
|
321
|
+
}
|
|
322
|
+
else
|
|
323
|
+
clone_url=$(provider_call "github" clone_url "$repo")
|
|
324
|
+
fi
|
|
325
|
+
git clone "$clone_url" "$local_path" || return 1
|
|
278
326
|
fi
|
|
279
327
|
fi
|
|
280
328
|
|
|
@@ -309,16 +357,14 @@ cmd_fix() {
|
|
|
309
357
|
fi
|
|
310
358
|
|
|
311
359
|
# Create metadata
|
|
312
|
-
local metadata
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
}
|
|
318
|
-
EOF
|
|
319
|
-
)
|
|
360
|
+
local metadata
|
|
361
|
+
metadata=$(jq -n \
|
|
362
|
+
--argjson issue_number "$issue_number" \
|
|
363
|
+
--arg issue_title "$issue_title" \
|
|
364
|
+
--arg issue_url "$issue_url" \
|
|
365
|
+
'{issue_number: $issue_number, issue_title: $issue_title, issue_url: $issue_url}')
|
|
320
366
|
|
|
321
|
-
psm_add_session "$session_id" "fix" "$alias" "issue-${issue_number}" "$branch_name" "$base" "$session_name" "$worktree_path" "$local_path" "$metadata"
|
|
367
|
+
psm_add_session "$session_id" "fix" "$alias" "issue-${issue_number}" "$branch_name" "$base" "$session_name" "$worktree_path" "$local_path" "$metadata" "$provider" "$provider_ref"
|
|
322
368
|
|
|
323
369
|
echo ""
|
|
324
370
|
log_success "Session ready!"
|
|
@@ -473,15 +519,20 @@ cmd_cleanup() {
|
|
|
473
519
|
|
|
474
520
|
local cleaned=0
|
|
475
521
|
|
|
476
|
-
# Check PR sessions (
|
|
522
|
+
# Check PR sessions (GitHub only)
|
|
477
523
|
while IFS='|' read -r id pr_number project; do
|
|
478
524
|
if [[ -z "$id" ]]; then continue; fi
|
|
479
525
|
|
|
526
|
+
local session_json=$(psm_get_session "$id")
|
|
527
|
+
local provider=$(echo "$session_json" | jq -r '.provider // "github"')
|
|
528
|
+
|
|
529
|
+
# Only GitHub has PRs
|
|
530
|
+
if [[ "$provider" != "github" ]]; then continue; fi
|
|
531
|
+
|
|
480
532
|
local repo=$(psm_get_project "$project" | cut -d'|' -f1)
|
|
481
533
|
|
|
482
534
|
if [[ -n "$repo" && -n "$pr_number" ]]; then
|
|
483
|
-
|
|
484
|
-
if [[ "$pr_state" == "true" ]]; then
|
|
535
|
+
if provider_github_available && provider_call "github" pr_merged "$pr_number" "$repo"; then
|
|
485
536
|
log_info "PR #${pr_number} is merged - cleaning up $id"
|
|
486
537
|
cmd_kill "$id"
|
|
487
538
|
((cleaned++))
|
|
@@ -489,18 +540,32 @@ cmd_cleanup() {
|
|
|
489
540
|
fi
|
|
490
541
|
done < <(psm_get_review_sessions)
|
|
491
542
|
|
|
492
|
-
# Check issue sessions (
|
|
543
|
+
# Check issue sessions (GitHub and Jira)
|
|
493
544
|
while IFS='|' read -r id issue_number project; do
|
|
494
545
|
if [[ -z "$id" ]]; then continue; fi
|
|
495
546
|
|
|
496
|
-
local
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
547
|
+
local session_json=$(psm_get_session "$id")
|
|
548
|
+
local provider=$(echo "$session_json" | jq -r '.provider // "github"')
|
|
549
|
+
local provider_ref=$(echo "$session_json" | jq -r '.provider_ref // empty')
|
|
550
|
+
|
|
551
|
+
if [[ "$provider" == "jira" ]]; then
|
|
552
|
+
# Jira cleanup
|
|
553
|
+
if provider_jira_available && [[ -n "$provider_ref" ]]; then
|
|
554
|
+
if provider_call "jira" issue_closed "$provider_ref"; then
|
|
555
|
+
log_info "Jira issue ${provider_ref} is done - cleaning up $id"
|
|
556
|
+
cmd_kill "$id"
|
|
557
|
+
((cleaned++))
|
|
558
|
+
fi
|
|
559
|
+
fi
|
|
560
|
+
else
|
|
561
|
+
# GitHub cleanup
|
|
562
|
+
local repo=$(psm_get_project "$project" | cut -d'|' -f1)
|
|
563
|
+
if provider_github_available && [[ -n "$repo" && -n "$issue_number" ]]; then
|
|
564
|
+
if provider_call "github" issue_closed "$issue_number" "$repo"; then
|
|
565
|
+
log_info "Issue #${issue_number} is closed - cleaning up $id"
|
|
566
|
+
cmd_kill "$id"
|
|
567
|
+
((cleaned++))
|
|
568
|
+
fi
|
|
504
569
|
fi
|
|
505
570
|
fi
|
|
506
571
|
done < <(psm_get_fix_sessions)
|