install: default jj setup in one-click flow
This commit is contained in:
97
README.md
97
README.md
@@ -33,6 +33,9 @@
|
|||||||
|
|
||||||
## 一键安装
|
## 一键安装
|
||||||
|
|
||||||
|
安装器现在会先安装 skill,再默认尝试安装 `jj`。
|
||||||
|
如果 `jj` 因本机环境、包管理器或网络原因安装失败,安装器不会失败,只会给出手动安装提示。
|
||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -55,6 +58,41 @@ powershell -NoProfile -ExecutionPolicy Bypass -Command "iwr -useb https://fun-md
|
|||||||
|
|
||||||
- `~/.codex/skills/gitea-issue-devops-agent`
|
- `~/.codex/skills/gitea-issue-devops-agent`
|
||||||
|
|
||||||
|
默认 `jj` 安装顺序:
|
||||||
|
|
||||||
|
- Linux / macOS:`brew -> cargo-binstall -> cargo`
|
||||||
|
- Windows:`winget -> scoop -> cargo`
|
||||||
|
|
||||||
|
安装控制项:
|
||||||
|
|
||||||
|
### Bash
|
||||||
|
|
||||||
|
```bash
|
||||||
|
INSTALL_JJ=0
|
||||||
|
JJ_INSTALL_METHOD=auto|brew|binstall|cargo
|
||||||
|
JJ_CHANNEL=release|prerelease
|
||||||
|
```
|
||||||
|
|
||||||
|
### PowerShell
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:INSTALL_JJ='0'
|
||||||
|
$env:JJ_INSTALL_METHOD='auto' # 或 winget / scoop / cargo
|
||||||
|
$env:JJ_CHANNEL='release' # 或 prerelease
|
||||||
|
```
|
||||||
|
|
||||||
|
验证命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
jj --version
|
||||||
|
jj config set --user user.name "Your Name"
|
||||||
|
jj config set --user user.email "you@example.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
详细说明:
|
||||||
|
|
||||||
|
- `skills/gitea-issue-devops-agent/references/jj-default-usage.md`
|
||||||
|
|
||||||
## 工具使用说明
|
## 工具使用说明
|
||||||
|
|
||||||
### issue_audit.py
|
### issue_audit.py
|
||||||
@@ -97,6 +135,11 @@ python skills/gitea-issue-devops-agent/scripts/preview_slot_allocator.py --state
|
|||||||
- `issue` 或固定 issue 触发来源
|
- `issue` 或固定 issue 触发来源
|
||||||
- 可选:`target_base`、`plan_path`、`reviewers`、`test_entry`、`deploy_env`、`health_endpoint`、`min_quality_score`、`jj_policy`
|
- 可选:`target_base`、`plan_path`、`reviewers`、`test_entry`、`deploy_env`、`health_endpoint`、`min_quality_score`、`jj_policy`
|
||||||
|
|
||||||
|
推荐默认值:
|
||||||
|
|
||||||
|
- `jj_policy=optional-internal`
|
||||||
|
- 先固定 issue,再进入 `Plan -> Draft PR -> 提测 -> 人工确认合并`
|
||||||
|
|
||||||
### Claude Code
|
### Claude Code
|
||||||
|
|
||||||
Skills 目录(官方支持):
|
Skills 目录(官方支持):
|
||||||
@@ -161,6 +204,14 @@ api_key=<TOKEN>
|
|||||||
mode=manual
|
mode=manual
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `jj` 在工作流中的定位
|
||||||
|
|
||||||
|
默认安装 `jj`,但不要求非工程角色理解 `jj`。
|
||||||
|
|
||||||
|
- 对外:继续使用 `issue / git branch / PR / CI/CD / review apps`
|
||||||
|
- 对内:用 `jj` 承担本地执行、回退、并行 workspace、变更重写
|
||||||
|
- 原则:`jj` 是内部可靠性增强层,不替代你们对外的 Git/Gitea 协作界面
|
||||||
|
|
||||||
## `skills` 命令参数释义(重点补充)
|
## `skills` 命令参数释义(重点补充)
|
||||||
|
|
||||||
> 本节把“`skills` 命令”统一理解为:在 Claude/Codex/OpenCode 中显式调用 `gitea-issue-devops-agent` 时提交的参数块。
|
> 本节把“`skills` 命令”统一理解为:在 Claude/Codex/OpenCode 中显式调用 `gitea-issue-devops-agent` 时提交的参数块。
|
||||||
@@ -213,6 +264,14 @@ min_quality_score=70
|
|||||||
|
|
||||||
适用:问题描述完整、团队希望最大化自动化吞吐。
|
适用:问题描述完整、团队希望最大化自动化吞吐。
|
||||||
|
|
||||||
|
典型流程:
|
||||||
|
|
||||||
|
1. 人工在 Gitea 选中 issue。
|
||||||
|
2. MajorAgent 生成 Plan 并创建分支、Draft PR。
|
||||||
|
3. SubAgent 只读取必要上下文并修改计划内路径。
|
||||||
|
4. TestAgent 跑单测、集成测试、issue 级 e2e。
|
||||||
|
5. 通过后进入 preview slot 和人工复核。
|
||||||
|
|
||||||
#### 场景 2:生产敏感仓库,人工确认每一步
|
#### 场景 2:生产敏感仓库,人工确认每一步
|
||||||
|
|
||||||
```text
|
```text
|
||||||
@@ -227,6 +286,13 @@ health_endpoint: /healthz
|
|||||||
|
|
||||||
适用:高风险改动、强合规流程、需要逐步确认分支/提交/提测/关闭。
|
适用:高风险改动、强合规流程、需要逐步确认分支/提交/提测/关闭。
|
||||||
|
|
||||||
|
典型流程:
|
||||||
|
|
||||||
|
1. 先生成 Plan。
|
||||||
|
2. 每次代码改动前都确认允许范围。
|
||||||
|
3. 提测、回写 issue、关闭 issue、最终 merge 都要人工确认。
|
||||||
|
4. 如 AI 偏航,可用 `jj` 做本地回退而不破坏外部 PR。
|
||||||
|
|
||||||
#### 场景 3:半自动协作,先评审后提测
|
#### 场景 3:半自动协作,先评审后提测
|
||||||
|
|
||||||
```text
|
```text
|
||||||
@@ -243,6 +309,13 @@ preview_slots=preview-a,preview-b,preview-c
|
|||||||
|
|
||||||
适用:多人协作项目,需要评审人显式批准后再进入提测和环境分配。
|
适用:多人协作项目,需要评审人显式批准后再进入提测和环境分配。
|
||||||
|
|
||||||
|
典型流程:
|
||||||
|
|
||||||
|
1. AI 先产出初始 Draft PR。
|
||||||
|
2. 工程师在 AI 编码工具里继续白盒调整。
|
||||||
|
3. reviewer 回复 `review-approved` 后才进入提测。
|
||||||
|
4. maintainer 最后确认 merge。
|
||||||
|
|
||||||
#### 场景 4:仅文档改动或轻量改动,资源最省策略
|
#### 场景 4:仅文档改动或轻量改动,资源最省策略
|
||||||
|
|
||||||
```text
|
```text
|
||||||
@@ -251,10 +324,34 @@ preview_slots=preview-a,preview-b,preview-c
|
|||||||
|
|
||||||
配合 `change_scope.py` 可自动得到 `skip` 或 `client_only`,避免不必要的服务端重启和环境开销。
|
配合 `change_scope.py` 可自动得到 `skip` 或 `client_only`,避免不必要的服务端重启和环境开销。
|
||||||
|
|
||||||
|
#### 场景 5:多 Agent 并行,但上下文不脑裂
|
||||||
|
|
||||||
|
```text
|
||||||
|
issue=48
|
||||||
|
mode=semi-automatic
|
||||||
|
jj_policy=optional-internal
|
||||||
|
plan_path=.tmp/devops-plans/devops-skills__issue-48.md
|
||||||
|
```
|
||||||
|
|
||||||
|
典型流程:
|
||||||
|
|
||||||
|
1. MajorAgent 只负责 issue 语义分析和 Plan。
|
||||||
|
2. SubAgent 只负责修改代码。
|
||||||
|
3. TestAgent 在独立 `jj workspace` 里验证。
|
||||||
|
4. 人工 reviewer 再决定是否继续迭代或合并。
|
||||||
|
|
||||||
|
适用:长流程、多角色协作、希望降低 token 消耗和上下文漂移。
|
||||||
|
|
||||||
## 技能路径
|
## 技能路径
|
||||||
|
|
||||||
- `skills/gitea-issue-devops-agent/SKILL.md`
|
- `skills/gitea-issue-devops-agent/SKILL.md`
|
||||||
|
|
||||||
|
## 核心文档
|
||||||
|
|
||||||
|
- `skills/gitea-issue-devops-agent/references/issue-template-standard.md`
|
||||||
|
- `skills/gitea-issue-devops-agent/references/plan-template.md`
|
||||||
|
- `skills/gitea-issue-devops-agent/references/jj-default-usage.md`
|
||||||
|
|
||||||
## 核心脚本
|
## 核心脚本
|
||||||
|
|
||||||
- `skills/gitea-issue-devops-agent/scripts/issue_audit.py`
|
- `skills/gitea-issue-devops-agent/scripts/issue_audit.py`
|
||||||
|
|||||||
@@ -0,0 +1,188 @@
|
|||||||
|
# Jj Default Installation Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** Make `jj` a default installation target in this repository's one-command installers without making installer success depend on `jj` success, and expand documentation with clearer usage instructions and scenario-based examples.
|
||||||
|
|
||||||
|
**Architecture:** Keep the public installer entrypoints unchanged while adding an internal second phase that attempts platform-appropriate `jj` installation. Preserve deterministic skill installation first, then run best-effort `jj` installation with explicit verification and manual fallback instructions.
|
||||||
|
|
||||||
|
**Tech Stack:** Bash, PowerShell, Git, README Markdown, skill reference docs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Chunk 1: Installer Behavior
|
||||||
|
|
||||||
|
### Task 1: Add plan-aware installer controls to the Bash installer
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `install/install.sh`
|
||||||
|
- Test: `install/install.sh` syntax via `bash -n`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Define installer controls**
|
||||||
|
|
||||||
|
Add environment-driven controls near the top of `install/install.sh`:
|
||||||
|
- `INSTALL_JJ` default `1`
|
||||||
|
- `JJ_INSTALL_METHOD` default `auto`
|
||||||
|
- `JJ_CHANNEL` default `release`
|
||||||
|
|
||||||
|
- [ ] **Step 2: Add `jj` install attempt helpers**
|
||||||
|
|
||||||
|
Implement focused functions for:
|
||||||
|
- logging
|
||||||
|
- command existence checks
|
||||||
|
- `brew` install path
|
||||||
|
- `cargo-binstall` install path
|
||||||
|
- `cargo install` fallback path
|
||||||
|
- manual fallback message
|
||||||
|
|
||||||
|
- [ ] **Step 3: Add OS-aware default attempt flow**
|
||||||
|
|
||||||
|
Implement this order:
|
||||||
|
- macOS: `brew`, then `cargo-binstall`, then `cargo`
|
||||||
|
- Linux: `brew` if available, then `cargo-binstall`, then `cargo`
|
||||||
|
|
||||||
|
- [ ] **Step 4: Keep skill installation authoritative**
|
||||||
|
|
||||||
|
Ensure the script:
|
||||||
|
- installs the skill first
|
||||||
|
- attempts `jj` only after the skill copy succeeds
|
||||||
|
- never exits non-zero only because `jj` failed
|
||||||
|
|
||||||
|
- [ ] **Step 5: Verify shell syntax**
|
||||||
|
|
||||||
|
Run: `bash -n install/install.sh`
|
||||||
|
Expected: no output, zero exit code
|
||||||
|
|
||||||
|
### Task 2: Add plan-aware installer controls to the PowerShell installer
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `install/install.ps1`
|
||||||
|
- Test: `install/install.ps1` parse check via PowerShell
|
||||||
|
|
||||||
|
- [ ] **Step 1: Define parameters and defaults**
|
||||||
|
|
||||||
|
Add parameters:
|
||||||
|
- `SkipJj`
|
||||||
|
- `JjInstallMethod = "auto"`
|
||||||
|
- `JjChannel = "release"`
|
||||||
|
|
||||||
|
- [ ] **Step 2: Add `jj` install attempt helpers**
|
||||||
|
|
||||||
|
Implement functions for:
|
||||||
|
- logging
|
||||||
|
- command existence checks
|
||||||
|
- `winget` install path
|
||||||
|
- `scoop` install path
|
||||||
|
- `cargo install` fallback path
|
||||||
|
- manual fallback message
|
||||||
|
|
||||||
|
- [ ] **Step 3: Add Windows attempt flow**
|
||||||
|
|
||||||
|
Implement this order:
|
||||||
|
- `winget`
|
||||||
|
- `scoop`
|
||||||
|
- `cargo`
|
||||||
|
|
||||||
|
- [ ] **Step 4: Keep installer non-blocking for `jj`**
|
||||||
|
|
||||||
|
Ensure skill installation still succeeds even if all `jj` attempts fail.
|
||||||
|
|
||||||
|
- [ ] **Step 5: Verify script parses**
|
||||||
|
|
||||||
|
Run: `powershell -NoProfile -Command "[void][scriptblock]::Create((Get-Content -Raw 'install/install.ps1'))"`
|
||||||
|
Expected: no output, zero exit code
|
||||||
|
|
||||||
|
## Chunk 2: Documentation
|
||||||
|
|
||||||
|
### Task 3: Expand README installation and usage guidance
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `README.md`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Update one-command install sections**
|
||||||
|
|
||||||
|
Document that installers now:
|
||||||
|
- install the skill
|
||||||
|
- attempt `jj` by default
|
||||||
|
- continue with warnings if `jj` cannot be installed automatically
|
||||||
|
|
||||||
|
- [ ] **Step 2: Add installer controls and verification**
|
||||||
|
|
||||||
|
Document:
|
||||||
|
- `INSTALL_JJ=0`
|
||||||
|
- `JJ_INSTALL_METHOD`
|
||||||
|
- `JJ_CHANNEL`
|
||||||
|
- PowerShell equivalents
|
||||||
|
- `jj --version`
|
||||||
|
- initial `jj config` commands
|
||||||
|
|
||||||
|
- [ ] **Step 3: Add richer scenario examples**
|
||||||
|
|
||||||
|
Include examples for:
|
||||||
|
- first-time team setup
|
||||||
|
- automatic bug fix flow
|
||||||
|
- semi-automatic engineering review flow
|
||||||
|
- manual hotfix flow
|
||||||
|
- multi-agent flow with `jj` workspaces
|
||||||
|
|
||||||
|
### Task 4: Add detailed `jj` usage guide
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `skills/gitea-issue-devops-agent/references/jj-default-usage.md`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Explain repository policy**
|
||||||
|
|
||||||
|
Document:
|
||||||
|
- `jj` is default to install
|
||||||
|
- `jj` is internal execution infrastructure
|
||||||
|
- Git branches/PRs/CI remain public system of record
|
||||||
|
|
||||||
|
- [ ] **Step 2: Explain verification and fallback**
|
||||||
|
|
||||||
|
Document:
|
||||||
|
- how to verify installation
|
||||||
|
- how to skip or force methods
|
||||||
|
- what to do when package managers are unavailable
|
||||||
|
|
||||||
|
- [ ] **Step 3: Add workflow examples**
|
||||||
|
|
||||||
|
Provide concrete examples for:
|
||||||
|
- issue -> plan -> draft PR
|
||||||
|
- engineer review after initial AI PR
|
||||||
|
- `jj workspace` for TestAgent and human reviewer
|
||||||
|
- rollback with operation log
|
||||||
|
|
||||||
|
## Chunk 3: Verification and Delivery
|
||||||
|
|
||||||
|
### Task 5: Verify, commit, and push
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: repo index and git history
|
||||||
|
|
||||||
|
- [ ] **Step 1: Run syntax checks**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
- `bash -n install/install.sh`
|
||||||
|
- `powershell -NoProfile -Command "[void][scriptblock]::Create((Get-Content -Raw 'install/install.ps1'))"`
|
||||||
|
|
||||||
|
Expected: both succeed
|
||||||
|
|
||||||
|
- [ ] **Step 2: Review diff**
|
||||||
|
|
||||||
|
Run: `git diff --check`
|
||||||
|
Expected: no diff formatting errors
|
||||||
|
|
||||||
|
- [ ] **Step 3: Commit**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
```bash
|
||||||
|
git add README.md install/install.sh install/install.ps1 docs/superpowers/plans/2026-03-13-jj-default-installation-plan.md skills/gitea-issue-devops-agent/references/jj-default-usage.md
|
||||||
|
git commit -m "docs: default jj installation in installers"
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 4: Push**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
```bash
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
param(
|
param(
|
||||||
[string]$RepoUrl = "https://fun-md.com/Fun_MD/devops-skills.git",
|
[string]$RepoUrl = "https://fun-md.com/Fun_MD/devops-skills.git",
|
||||||
[string]$CodexHome = "$HOME\.codex"
|
[string]$CodexHome = "$HOME\.codex",
|
||||||
|
[switch]$SkipJj,
|
||||||
|
[ValidateSet("auto", "winget", "scoop", "cargo")]
|
||||||
|
[string]$JjInstallMethod = $(if ($env:JJ_INSTALL_METHOD) { $env:JJ_INSTALL_METHOD } else { "auto" }),
|
||||||
|
[ValidateSet("release", "prerelease")]
|
||||||
|
[string]$JjChannel = $(if ($env:JJ_CHANNEL) { $env:JJ_CHANNEL } else { "release" })
|
||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
@@ -8,13 +13,136 @@ $ErrorActionPreference = "Stop"
|
|||||||
$skillName = "gitea-issue-devops-agent"
|
$skillName = "gitea-issue-devops-agent"
|
||||||
$targetDir = Join-Path $CodexHome "skills\$skillName"
|
$targetDir = Join-Path $CodexHome "skills\$skillName"
|
||||||
$tmpRoot = Join-Path $env:TEMP ("devops-skills-" + [Guid]::NewGuid().ToString("N"))
|
$tmpRoot = Join-Path $env:TEMP ("devops-skills-" + [Guid]::NewGuid().ToString("N"))
|
||||||
|
$installJj = $true
|
||||||
|
if ($SkipJj.IsPresent) {
|
||||||
|
$installJj = $false
|
||||||
|
}
|
||||||
|
if ($env:INSTALL_JJ -and $env:INSTALL_JJ -eq "0") {
|
||||||
|
$installJj = $false
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-InstallLog {
|
||||||
|
param([string]$Message)
|
||||||
|
Write-Host "[install] $Message"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-InstallWarn {
|
||||||
|
param([string]$Message)
|
||||||
|
Write-Warning "[install] $Message"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-CommandAvailable {
|
||||||
|
param([string]$Name)
|
||||||
|
return $null -ne (Get-Command $Name -ErrorAction SilentlyContinue)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Show-JjManualHelp {
|
||||||
|
Write-InstallWarn "jj was not installed automatically."
|
||||||
|
Write-InstallWarn "Manual options:"
|
||||||
|
Write-InstallWarn " - winget install jj-vcs.jj"
|
||||||
|
Write-InstallWarn " - scoop install main/jj"
|
||||||
|
if ($JjChannel -eq "prerelease") {
|
||||||
|
Write-InstallWarn " - cargo install --git https://github.com/jj-vcs/jj.git --locked --bin jj jj-cli"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-InstallWarn " - cargo install --locked --bin jj jj-cli"
|
||||||
|
}
|
||||||
|
Write-InstallWarn "After installation, verify with: jj --version"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Install-JjWithWinget {
|
||||||
|
if (-not (Test-CommandAvailable winget)) {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
if ($JjChannel -ne "release") {
|
||||||
|
Write-InstallWarn "winget path skipped because prerelease jj is requested."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-InstallLog "attempting jj installation via winget"
|
||||||
|
& winget install --id jj-vcs.jj -e --accept-source-agreements --accept-package-agreements
|
||||||
|
return $LASTEXITCODE -eq 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function Install-JjWithScoop {
|
||||||
|
if (-not (Test-CommandAvailable scoop)) {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
if ($JjChannel -ne "release") {
|
||||||
|
Write-InstallWarn "scoop path skipped because prerelease jj is requested."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-InstallLog "attempting jj installation via scoop"
|
||||||
|
& scoop install main/jj
|
||||||
|
return $LASTEXITCODE -eq 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function Install-JjWithCargo {
|
||||||
|
if (-not (Test-CommandAvailable cargo)) {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-InstallLog "attempting jj installation via cargo"
|
||||||
|
if ($JjChannel -eq "prerelease") {
|
||||||
|
& cargo install --git https://github.com/jj-vcs/jj.git --locked --bin jj jj-cli
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
& cargo install --locked --bin jj jj-cli
|
||||||
|
}
|
||||||
|
return $LASTEXITCODE -eq 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-JjInstall {
|
||||||
|
if (-not $installJj) {
|
||||||
|
Write-InstallLog "skipping jj installation because INSTALL_JJ=0 or -SkipJj was provided"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Test-CommandAvailable jj) {
|
||||||
|
Write-InstallLog "jj already installed: $(& jj --version)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$installed = $false
|
||||||
|
switch ($JjInstallMethod) {
|
||||||
|
"auto" {
|
||||||
|
$installed = (Install-JjWithWinget) -or (Install-JjWithScoop) -or (Install-JjWithCargo)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
"winget" {
|
||||||
|
$installed = Install-JjWithWinget
|
||||||
|
break
|
||||||
|
}
|
||||||
|
"scoop" {
|
||||||
|
$installed = Install-JjWithScoop
|
||||||
|
break
|
||||||
|
}
|
||||||
|
"cargo" {
|
||||||
|
$installed = Install-JjWithCargo
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $installed) {
|
||||||
|
Show-JjManualHelp
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Test-CommandAvailable jj) {
|
||||||
|
Write-InstallLog "jj installation succeeded: $(& jj --version)"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Show-JjManualHelp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
|
if (-not (Test-CommandAvailable git)) {
|
||||||
throw "[install] git is required but not found."
|
throw "[install] git is required but not found."
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host "[install] downloading $skillName from $RepoUrl"
|
Write-InstallLog "downloading $skillName from $RepoUrl"
|
||||||
git clone --depth 1 $RepoUrl $tmpRoot | Out-Null
|
git clone --depth 1 $RepoUrl $tmpRoot | Out-Null
|
||||||
|
|
||||||
$sourceDir = Join-Path $tmpRoot "skills\$skillName"
|
$sourceDir = Join-Path $tmpRoot "skills\$skillName"
|
||||||
@@ -28,8 +156,10 @@ try {
|
|||||||
}
|
}
|
||||||
Copy-Item -Path $sourceDir -Destination $targetDir -Recurse -Force
|
Copy-Item -Path $sourceDir -Destination $targetDir -Recurse -Force
|
||||||
|
|
||||||
Write-Host "[install] done"
|
Write-InstallLog "skill installed"
|
||||||
Write-Host "[install] installed path: $targetDir"
|
Write-InstallLog "installed path: $targetDir"
|
||||||
|
Invoke-JjInstall
|
||||||
|
Write-InstallLog "done"
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if (Test-Path $tmpRoot) {
|
if (Test-Path $tmpRoot) {
|
||||||
|
|||||||
@@ -6,6 +6,119 @@ SKILL_NAME="gitea-issue-devops-agent"
|
|||||||
CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
|
CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
|
||||||
TARGET_DIR="${CODEX_HOME}/skills/${SKILL_NAME}"
|
TARGET_DIR="${CODEX_HOME}/skills/${SKILL_NAME}"
|
||||||
TMP_DIR="$(mktemp -d)"
|
TMP_DIR="$(mktemp -d)"
|
||||||
|
INSTALL_JJ="${INSTALL_JJ:-1}"
|
||||||
|
JJ_INSTALL_METHOD="${JJ_INSTALL_METHOD:-auto}"
|
||||||
|
JJ_CHANNEL="${JJ_CHANNEL:-release}"
|
||||||
|
|
||||||
|
log() {
|
||||||
|
echo "[install] $*"
|
||||||
|
}
|
||||||
|
|
||||||
|
warn() {
|
||||||
|
echo "[install] warning: $*" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
manual_jj_help() {
|
||||||
|
warn "jj was not installed automatically."
|
||||||
|
warn "Manual options:"
|
||||||
|
warn " - Homebrew: brew install jj"
|
||||||
|
warn " - cargo-binstall: cargo binstall --strategies crate-meta-data jj-cli"
|
||||||
|
if [ "$JJ_CHANNEL" = "prerelease" ]; then
|
||||||
|
warn " - cargo prerelease: cargo install --git https://github.com/jj-vcs/jj.git --locked --bin jj jj-cli"
|
||||||
|
else
|
||||||
|
warn " - cargo release: cargo install --locked --bin jj jj-cli"
|
||||||
|
fi
|
||||||
|
warn "After installation, verify with: jj --version"
|
||||||
|
}
|
||||||
|
|
||||||
|
install_jj_with_brew() {
|
||||||
|
if ! command -v brew >/dev/null 2>&1; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ "$JJ_CHANNEL" != "release" ]; then
|
||||||
|
warn "brew path skipped because prerelease jj is requested."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "attempting jj installation via Homebrew"
|
||||||
|
brew install jj
|
||||||
|
}
|
||||||
|
|
||||||
|
install_jj_with_binstall() {
|
||||||
|
if ! command -v cargo >/dev/null 2>&1 || ! command -v cargo-binstall >/dev/null 2>&1; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ "$JJ_CHANNEL" != "release" ]; then
|
||||||
|
warn "cargo-binstall path skipped because prerelease jj is requested."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "attempting jj installation via cargo-binstall"
|
||||||
|
cargo binstall --strategies crate-meta-data jj-cli
|
||||||
|
}
|
||||||
|
|
||||||
|
install_jj_with_cargo() {
|
||||||
|
if ! command -v cargo >/dev/null 2>&1; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "attempting jj installation via cargo"
|
||||||
|
if [ "$JJ_CHANNEL" = "prerelease" ]; then
|
||||||
|
cargo install --git https://github.com/jj-vcs/jj.git --locked --bin jj jj-cli
|
||||||
|
else
|
||||||
|
cargo install --locked --bin jj jj-cli
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
attempt_jj_install() {
|
||||||
|
if [ "$INSTALL_JJ" = "0" ]; then
|
||||||
|
log "skipping jj installation because INSTALL_JJ=0"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v jj >/dev/null 2>&1; then
|
||||||
|
log "jj already installed: $(jj --version)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$JJ_INSTALL_METHOD" in
|
||||||
|
auto)
|
||||||
|
install_jj_with_brew || install_jj_with_binstall || install_jj_with_cargo || {
|
||||||
|
manual_jj_help
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
;;
|
||||||
|
brew)
|
||||||
|
install_jj_with_brew || {
|
||||||
|
manual_jj_help
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
;;
|
||||||
|
binstall)
|
||||||
|
install_jj_with_binstall || {
|
||||||
|
manual_jj_help
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
;;
|
||||||
|
cargo)
|
||||||
|
install_jj_with_cargo || {
|
||||||
|
manual_jj_help
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
warn "unsupported JJ_INSTALL_METHOD='$JJ_INSTALL_METHOD'; skipping jj install."
|
||||||
|
manual_jj_help
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if command -v jj >/dev/null 2>&1; then
|
||||||
|
log "jj installation succeeded: $(jj --version)"
|
||||||
|
else
|
||||||
|
manual_jj_help
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
rm -rf "$TMP_DIR"
|
rm -rf "$TMP_DIR"
|
||||||
@@ -13,15 +126,15 @@ cleanup() {
|
|||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
if ! command -v git >/dev/null 2>&1; then
|
if ! command -v git >/dev/null 2>&1; then
|
||||||
echo "[install] git is required but not found."
|
log "git is required but not found."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "[install] downloading ${SKILL_NAME} from ${REPO_URL}"
|
log "downloading ${SKILL_NAME} from ${REPO_URL}"
|
||||||
git clone --depth 1 "$REPO_URL" "$TMP_DIR/repo" >/dev/null 2>&1
|
git clone --depth 1 "$REPO_URL" "$TMP_DIR/repo" >/dev/null 2>&1
|
||||||
|
|
||||||
if [ ! -d "$TMP_DIR/repo/skills/${SKILL_NAME}" ]; then
|
if [ ! -d "$TMP_DIR/repo/skills/${SKILL_NAME}" ]; then
|
||||||
echo "[install] skill directory not found in repository."
|
log "skill directory not found in repository."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -29,5 +142,7 @@ mkdir -p "${CODEX_HOME}/skills"
|
|||||||
rm -rf "$TARGET_DIR"
|
rm -rf "$TARGET_DIR"
|
||||||
cp -R "$TMP_DIR/repo/skills/${SKILL_NAME}" "$TARGET_DIR"
|
cp -R "$TMP_DIR/repo/skills/${SKILL_NAME}" "$TARGET_DIR"
|
||||||
|
|
||||||
echo "[install] done"
|
log "skill installed"
|
||||||
echo "[install] installed path: ${TARGET_DIR}"
|
log "installed path: ${TARGET_DIR}"
|
||||||
|
attempt_jj_install
|
||||||
|
log "done"
|
||||||
|
|||||||
@@ -414,6 +414,7 @@ Use `jj` only under these rules:
|
|||||||
- `references/triage-standard.md`: scoring rubric and templates for needs-info, review request, test submission, and merge approval.
|
- `references/triage-standard.md`: scoring rubric and templates for needs-info, review request, test submission, and merge approval.
|
||||||
- `references/issue-template-standard.md`: standard issue templates for `bug`, `enhancement`, and `feature`.
|
- `references/issue-template-standard.md`: standard issue templates for `bug`, `enhancement`, and `feature`.
|
||||||
- `references/plan-template.md`: default plan structure and status machine for MajorAgent/SubAgent/TestAgent handoff.
|
- `references/plan-template.md`: default plan structure and status machine for MajorAgent/SubAgent/TestAgent handoff.
|
||||||
|
- `references/jj-default-usage.md`: default `jj` installation strategy, verification, and scenario-based usage guidance.
|
||||||
|
|
||||||
## Operational Constraints
|
## Operational Constraints
|
||||||
|
|
||||||
|
|||||||
170
skills/gitea-issue-devops-agent/references/jj-default-usage.md
Normal file
170
skills/gitea-issue-devops-agent/references/jj-default-usage.md
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
# Jj Default Installation and Usage
|
||||||
|
|
||||||
|
This repository installs the `gitea-issue-devops-agent` skill first, then attempts to install `jj` by default.
|
||||||
|
|
||||||
|
`jj` is the internal execution layer for agent reliability. Git branches, PRs, CI/CD pipelines, and merge approvals remain the external system of record.
|
||||||
|
|
||||||
|
## Default Install Strategy
|
||||||
|
|
||||||
|
The one-command installers now behave like this:
|
||||||
|
|
||||||
|
1. Install the skill into the target Codex directory.
|
||||||
|
2. Check whether `jj` is already available.
|
||||||
|
3. If not, try OS-specific install methods.
|
||||||
|
4. If all methods fail, keep the skill installed and print manual fallback instructions.
|
||||||
|
|
||||||
|
## OS-Specific Attempt Order
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
- `brew install jj`
|
||||||
|
- `cargo binstall --strategies crate-meta-data jj-cli`
|
||||||
|
- `cargo install --locked --bin jj jj-cli`
|
||||||
|
|
||||||
|
For prerelease:
|
||||||
|
|
||||||
|
- `cargo install --git https://github.com/jj-vcs/jj.git --locked --bin jj jj-cli`
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
- `brew install jj`
|
||||||
|
- `cargo binstall --strategies crate-meta-data jj-cli`
|
||||||
|
- `cargo install --locked --bin jj jj-cli`
|
||||||
|
|
||||||
|
For prerelease:
|
||||||
|
|
||||||
|
- `cargo install --git https://github.com/jj-vcs/jj.git --locked --bin jj jj-cli`
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
- `winget install jj-vcs.jj`
|
||||||
|
- `scoop install main/jj`
|
||||||
|
- `cargo install --locked --bin jj jj-cli`
|
||||||
|
|
||||||
|
For prerelease:
|
||||||
|
|
||||||
|
- `cargo install --git https://github.com/jj-vcs/jj.git --locked --bin jj jj-cli`
|
||||||
|
|
||||||
|
## Installer Controls
|
||||||
|
|
||||||
|
### Bash installers
|
||||||
|
|
||||||
|
- `INSTALL_JJ=0`: skip `jj` installation
|
||||||
|
- `JJ_INSTALL_METHOD=auto|brew|binstall|cargo`
|
||||||
|
- `JJ_CHANNEL=release|prerelease`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
INSTALL_JJ=0 curl -fsSL https://fun-md.com/Fun_MD/devops-skills/raw/branch/main/install/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
JJ_INSTALL_METHOD=cargo JJ_CHANNEL=prerelease curl -fsSL https://fun-md.com/Fun_MD/devops-skills/raw/branch/main/install/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
### PowerShell installers
|
||||||
|
|
||||||
|
With the one-liner, prefer environment variables:
|
||||||
|
|
||||||
|
- `$env:INSTALL_JJ='0'`
|
||||||
|
- `$env:JJ_INSTALL_METHOD='auto'|'winget'|'scoop'|'cargo'`
|
||||||
|
- `$env:JJ_CHANNEL='release'|'prerelease'`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:JJ_INSTALL_METHOD='winget'
|
||||||
|
iwr -useb https://fun-md.com/Fun_MD/devops-skills/raw/branch/main/install/install.ps1 | iex
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:INSTALL_JJ='0'
|
||||||
|
iwr -useb https://fun-md.com/Fun_MD/devops-skills/raw/branch/main/install/install.ps1 | iex
|
||||||
|
```
|
||||||
|
|
||||||
|
If you save the script locally first, you can also use the `-SkipJj`, `-JjInstallMethod`, and `-JjChannel` parameters directly.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
After installation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
jj --version
|
||||||
|
```
|
||||||
|
|
||||||
|
Set identity:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
jj config set --user user.name "Your Name"
|
||||||
|
jj config set --user user.email "you@example.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
Optional shell completion:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source <(jj util completion bash)
|
||||||
|
```
|
||||||
|
|
||||||
|
PowerShell completion:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
jj util completion power-shell | Out-String | Invoke-Expression
|
||||||
|
```
|
||||||
|
|
||||||
|
## Working Model
|
||||||
|
|
||||||
|
Use `jj` as an internal operator tool:
|
||||||
|
|
||||||
|
- issue selection, branch naming, PR creation, CI, and merge stay Git/Gitea-native
|
||||||
|
- `jj` handles local history rewrites, workspace isolation, and recovery
|
||||||
|
- each issue branch can map to one `jj` bookmark
|
||||||
|
|
||||||
|
## Scenario Examples
|
||||||
|
|
||||||
|
### 1) First-Time Team Setup
|
||||||
|
|
||||||
|
1. Run the one-command installer.
|
||||||
|
2. Verify `jj --version`.
|
||||||
|
3. Configure `user.name` and `user.email`.
|
||||||
|
4. Start with one fixed issue in `manual` or `semi-automatic` mode.
|
||||||
|
|
||||||
|
Recommended when a team is new to AI-assisted delivery and wants controlled adoption.
|
||||||
|
|
||||||
|
### 2) Initial AI PR for a Bug
|
||||||
|
|
||||||
|
1. Human selects issue `#48`.
|
||||||
|
2. MajorAgent creates the plan.
|
||||||
|
3. Issue branch and draft PR are created.
|
||||||
|
4. SubAgent changes only the planned paths.
|
||||||
|
5. TestAgent validates build, targeted tests, and issue e2e.
|
||||||
|
6. Engineer reviews and refines before merge approval.
|
||||||
|
|
||||||
|
Recommended default flow for day-to-day bug fixing.
|
||||||
|
|
||||||
|
### 3) Semi-Automatic Review Flow
|
||||||
|
|
||||||
|
1. AI produces the initial draft PR.
|
||||||
|
2. Reviewer inspects the plan, diff scope, and evidence.
|
||||||
|
3. Engineer uses the AI coding tool for follow-up edits if needed.
|
||||||
|
4. Only after review approval does the branch enter preview-slot testing.
|
||||||
|
|
||||||
|
Recommended when engineering review must happen before environment allocation.
|
||||||
|
|
||||||
|
### 4) Human + TestAgent Parallel Verification with Workspaces
|
||||||
|
|
||||||
|
1. SubAgent works in the main issue workspace.
|
||||||
|
2. TestAgent creates a separate `jj workspace` for validation.
|
||||||
|
3. Human reviewer can create another workspace for white-box adjustments.
|
||||||
|
4. All three flows remain tied to the same issue branch and plan.
|
||||||
|
|
||||||
|
Recommended for larger issues where testing and code refinement happen in parallel.
|
||||||
|
|
||||||
|
### 5) Recovery After AI Drift
|
||||||
|
|
||||||
|
1. AI rewrites the change incorrectly or edits too broadly.
|
||||||
|
2. Engineer inspects `jj op log`.
|
||||||
|
3. Engineer uses `jj undo`, `jj op revert`, or `jj op restore`.
|
||||||
|
4. The issue branch and PR remain intact while local execution history is repaired.
|
||||||
|
|
||||||
|
Recommended when AI behavior is fast but unreliable and quick recovery matters.
|
||||||
Reference in New Issue
Block a user