aidevops 3.5.896 → 3.8.2
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/README.md +96 -16
- package/VERSION +1 -1
- package/aidevops.sh +293 -34
- package/package.json +1 -1
- package/setup-modules/agent-deploy.sh +297 -669
- package/setup-modules/agent-runtime.sh +251 -0
- package/setup-modules/config.sh +83 -0
- package/setup-modules/core.sh +2 -0
- package/setup-modules/mcp-setup.sh +2 -0
- package/setup-modules/migrations.sh +267 -1
- package/setup-modules/plugins.sh +2 -0
- package/setup-modules/post-setup.sh +8 -1
- package/setup-modules/schedulers.sh +762 -336
- package/setup-modules/shell-env.sh +54 -16
- package/setup-modules/tool-beads.sh +324 -0
- package/setup-modules/tool-install.sh +6 -1
- package/setup.sh +207 -2
- package/templates/deploy-templates.sh +2 -0
- package/templates/home/.agents/README.md +3 -0
- package/templates/home/AGENTS.md +3 -0
- package/templates/home/git/.agent/README.md +3 -0
- package/templates/home/git/AGENTS.md +3 -0
- package/templates/opencode-config-agents.md +3 -0
- package/templates/standard-functions.sh +2 -0
- package/templates/wordpress-performance-workflow.md +3 -0
package/README.md
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
<!-- SPDX-FileCopyrightText: 2025-2026 Marcus Quinn -->
|
|
3
|
+
|
|
1
4
|
# AI DevOps Framework
|
|
2
5
|
|
|
3
6
|
**[aidevops.sh](https://aidevops.sh)** — An [OpenCode](https://opencode.ai/) plugin and AI operations platform for launching and managing development, business, marketing, and creative projects. 13 specialist AI agents handle the automatable work across every domain so your time is preserved for real-world discovery and decisions that AI cannot yet reach.
|
|
@@ -188,7 +191,8 @@ git clone https://github.com/marcusquinn/aidevops.git ~/Git/aidevops
|
|
|
188
191
|
- Configure your AI assistants automatically
|
|
189
192
|
- Offer to install Oh My Zsh (optional, opt-in) for enhanced shell experience
|
|
190
193
|
- Guide you through recommended tools (Tabby, Zed, Git CLIs)
|
|
191
|
-
- Ensure all PATH and alias changes work in both bash and
|
|
194
|
+
- Ensure all PATH and alias changes work in both bash, zsh, and fish
|
|
195
|
+
- Add a `claude` alias that runs `claude --dangerously-skip-permissions` (skips per-tool permission prompts). Re-running setup updates the alias automatically. To grant permissions per-session instead, press **Shift-Tab** inside Claude Code to cycle through permission modes (default → skip permissions → auto-approve).
|
|
192
196
|
|
|
193
197
|
**New users: Start [OpenCode](https://opencode.ai/) and type `/onboarding`** to configure your services interactively. OpenCode is the recommended tool for aidevops - all features, agents, and workflows are designed and tested for it first. The onboarding wizard will:
|
|
194
198
|
- Explain what **[aidevops](https://aidevops.sh)** can do
|
|
@@ -1792,25 +1796,67 @@ Call them in your AI assistant conversation with a simple @mention
|
|
|
1792
1796
|
|
|
1793
1797
|
### **Main Agents**
|
|
1794
1798
|
|
|
1795
|
-
Primary agents
|
|
1799
|
+
Primary agents live at `.agents/<name>.md`. Each is a domain expert with its own system prompt, tool permissions, and subagent roster. MCPs are loaded on-demand per subagent, not per primary agent.
|
|
1796
1800
|
|
|
1797
1801
|
| Name | File | Purpose | Model Tier |
|
|
1798
1802
|
|------|------|---------|------------|
|
|
1799
|
-
| Build+ | `build-plus.md` |
|
|
1803
|
+
| Build+ | `build-plus.md` | Code: features, bug fixes, refactors, CI, full-loop delivery (default) | opus |
|
|
1800
1804
|
| Automate | `automate.md` | Scheduling, dispatch, monitoring, background orchestration | sonnet |
|
|
1801
|
-
|
|
|
1802
|
-
| Business | `business.md` | Company orchestration
|
|
1803
|
-
| Content | `content.md` | Content creation
|
|
1804
|
-
| Health | `health.md` | Health and wellness | opus |
|
|
1805
|
-
| Legal | `legal.md` | Legal compliance | opus |
|
|
1806
|
-
| Marketing | `marketing.md` |
|
|
1807
|
-
|
|
|
1808
|
-
|
|
|
1809
|
-
| SEO | `seo.md` | SEO
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1805
|
+
| Aidevops | `aidevops.md` | Framework development — meta-agent for improving aidevops itself | opus |
|
|
1806
|
+
| Business | `business.md` | Company orchestration, financial ops, invoicing, strategy | sonnet |
|
|
1807
|
+
| Content | `content.md` | Content creation across blog, video, audio, image, social | opus |
|
|
1808
|
+
| Health | `health.md` | Health and wellness content, fitness, nutrition | opus |
|
|
1809
|
+
| Legal | `legal.md` | Legal compliance, terms, privacy, GDPR | opus |
|
|
1810
|
+
| Marketing-Sales | `marketing-sales.md` | Email campaigns, CRM, outreach, paid ads, direct response, CRO | opus |
|
|
1811
|
+
| Product | `product.md` | Product management, PRDs, roadmaps, requirements capture | opus |
|
|
1812
|
+
| Research | `research.md` | Technical and market research, competitive analysis | gemini/grok |
|
|
1813
|
+
| SEO | `seo.md` | SEO audits, keyword research, GSC, schema, technical SEO | opus |
|
|
1814
|
+
|
|
1815
|
+
**Specialist subagents** (e.g. `@wordpress`, `@seo`, Build-Agent, Build-MCP, etc.) live under `.agents/tools/` or as `mode: subagent` files and are invoked via `@mention` when domain expertise is needed. See `subagent-index.toon` for the full roster.
|
|
1816
|
+
|
|
1817
|
+
#### How to invoke a main agent
|
|
1818
|
+
|
|
1819
|
+
| Client | Invocation |
|
|
1820
|
+
|---|---|
|
|
1821
|
+
| **OpenCode** | Tab through the agent picker in the UI — Build+ is the default. Main agents are registered as top-level agents in OpenCode's config. |
|
|
1822
|
+
| **Claude Code / Codex / Cursor / Droid / Kiro / Continue / Kimi / Qwen / Amp / Windsurf / Gemini CLI** | Slash command, namespaced with the `aidevops-` prefix: `/aidevops-build-plus`, `/aidevops-automate`, `/aidevops-seo`, etc. |
|
|
1823
|
+
| **Aider** | No native slash command support — use a shell alias: `alias aider-build='aider --message-file ~/.aidevops/agents/build-plus.md'`. |
|
|
1824
|
+
|
|
1825
|
+
The `aidevops-` prefix differentiates framework commands from each client's native slash commands and groups them alphabetically in the command picker. It applies to **every** aidevops slash command — not just main agents — so `/aidevops-preflight`, `/aidevops-release`, `/aidevops-commit` etc. all sort together in your `/` menu.
|
|
1826
|
+
|
|
1827
|
+
#### Supported AI clients (14)
|
|
1828
|
+
|
|
1829
|
+
The framework installs itself across these clients. Slash commands, agent definitions, and (optionally) session-memory mining are wired up per-client by `setup.sh`, gated on per-client feature flags in `.agents/scripts/runtime-registry.sh`.
|
|
1830
|
+
|
|
1831
|
+
| Client | Slash commands | Agent dir | Memory mining | Notes |
|
|
1832
|
+
|---|---|---|---|---|
|
|
1833
|
+
| OpenCode | ✅ `~/.config/opencode/command/` | config-based | ✅ default | Native tab-through primary agents |
|
|
1834
|
+
| Claude Code | ✅ `~/.claude/commands/` | ✅ `~/.claude/agents/` | ✅ default | Full feature parity |
|
|
1835
|
+
| Codex CLI | ✅ `~/.codex/prompts/` | — | ✅ default | Invoked as `/prompts:aidevops-<name>` |
|
|
1836
|
+
| Cursor | ✅ `~/.cursor/commands/` (≥1.6) | ✅ `~/.cursor/agents/` | ✅ default | Frontmatter stripped (not supported) |
|
|
1837
|
+
| Droid (Factory) | ✅ `~/.factory/commands/` | — | opt-in | — |
|
|
1838
|
+
| Gemini CLI | ✅ `~/.gemini/commands/` | — | opt-in | Converted to TOML (`prompt = """..."""`) |
|
|
1839
|
+
| Kimi CLI | ✅ `~/.kimi/skills/<name>/SKILL.md` | ✅ `~/.kimi/agents/` | opt-in | Directory-per-skill + auto `name:` matching |
|
|
1840
|
+
| Qwen Code | ✅ `~/.qwen/commands/` | ✅ `~/.qwen/agents/` | opt-in | Sub-agents + skills |
|
|
1841
|
+
| Continue | ✅ `~/.continue/prompts/` | — | opt-in | `.prompt` ext + `invokable: true` |
|
|
1842
|
+
| Kiro | ✅ `~/.kiro/steering/` | — | opt-in | `inclusion: manual` for slash access |
|
|
1843
|
+
| Kilo Code | custom modes | — | opt-in | Uses modes instead of commands |
|
|
1844
|
+
| Windsurf | repo-local `.windsurf/workflows/` | — | ❌ (protobuf) | Symlinked by `aidevops init` |
|
|
1845
|
+
| Amp (Sourcegraph) | repo-local `.agents/commands/` | ✅ `~/.amp/agents/` | ❌ (cloud) | Path match is native |
|
|
1846
|
+
| Aider | shell alias workaround | — | ❌ (per-repo md) | Native custom commands open upstream |
|
|
1847
|
+
|
|
1848
|
+
**Feature flags** per client (`agents` / `commands` / `memory`) live in `runtime-registry.sh` and can be overridden at install time via environment variables:
|
|
1849
|
+
|
|
1850
|
+
```bash
|
|
1851
|
+
AIDEVOPS_FEATURE_MEMORY_CLAUDE_CODE=no setup.sh
|
|
1852
|
+
AIDEVOPS_FEATURE_COMMANDS_CURSOR=no setup.sh
|
|
1853
|
+
```
|
|
1854
|
+
|
|
1855
|
+
Memory mining defaults are deliberately conservative: only OpenCode, Claude Code, Codex, and Cursor are opted in by default. All other clients default to off — enable them case-by-case after reviewing what the mining job will read.
|
|
1856
|
+
|
|
1857
|
+
#### Endgame: progressive disclosure
|
|
1858
|
+
|
|
1859
|
+
The long-term direction is to make slash commands and `@mentions` unnecessary altogether. A progressive disclosure layer should load the right domain agents and tools into context based on the nature of the conversation — you should never have to remember agent names or prefix commands. The `aidevops-` slash commands documented above are a stepping stone: they standardise routing across every client we support, and will eventually be auto-invoked by the router rather than typed by hand.
|
|
1814
1860
|
|
|
1815
1861
|
### **Example Subagents with MCP Integration**
|
|
1816
1862
|
|
|
@@ -2284,6 +2330,40 @@ memory-helper.sh recall "refactor auth middleware" --semantic
|
|
|
2284
2330
|
|
|
2285
2331
|
**Storage:** `~/.aidevops/.agent-workspace/memory/memory.db` (+ optional `embeddings.db` for semantic search, `namespaces/` for per-runner isolation)
|
|
2286
2332
|
|
|
2333
|
+
#### Session mining (cross-client)
|
|
2334
|
+
|
|
2335
|
+
Beyond explicit `/remember` calls, aidevops can harvest structured session data from each supported AI client's on-disk conversation history. This turns every prior session — regardless of which tool you were using — into searchable context for future sessions.
|
|
2336
|
+
|
|
2337
|
+
Per-client storage paths and formats (see `runtime-registry.sh`):
|
|
2338
|
+
|
|
2339
|
+
| Client | Storage path | Format | Default |
|
|
2340
|
+
|---|---|---|---|
|
|
2341
|
+
| OpenCode | `~/.local/share/opencode/opencode.db` | SQLite | ✅ on |
|
|
2342
|
+
| Claude Code | `~/.claude/projects/` | JSONL per project | ✅ on |
|
|
2343
|
+
| Codex CLI | `~/.codex/sessions/` | JSONL, date-partitioned | ✅ on |
|
|
2344
|
+
| Cursor | `~/Library/Application Support/Cursor/User/workspaceStorage/` | SQLite (`state.vscdb`) | ✅ on |
|
|
2345
|
+
| Droid | `~/.factory/sessions/` | JSONL per session | opt-in |
|
|
2346
|
+
| Gemini CLI | `~/.gemini/tmp/` | JSON per session | opt-in |
|
|
2347
|
+
| Continue | `~/.continue/sessions/` | JSON per session | opt-in |
|
|
2348
|
+
| Kilo Code | `~/Library/.../kilocode.kilo-code/tasks/` | JSON (Anthropic schema) | opt-in |
|
|
2349
|
+
| Kiro | `~/Library/Application Support/Kiro/User/workspaceStorage/` | SQLite | opt-in |
|
|
2350
|
+
| Kimi CLI | `~/.kimi/sessions/<id>/context.jsonl` | JSONL | opt-in |
|
|
2351
|
+
| Qwen Code | `~/.qwen/tmp/` | JSON per session | opt-in |
|
|
2352
|
+
| Windsurf | `~/.codeium/windsurf/cascade/` | protobuf (opaque) | ❌ unsupported |
|
|
2353
|
+
| Amp | server-side (cloud) | needs API auth | ❌ unsupported |
|
|
2354
|
+
| Aider | `<repo>/.aider.chat.history.md` | markdown transcript | ❌ unsupported |
|
|
2355
|
+
|
|
2356
|
+
**Defaults are deliberately conservative.** Only the four tier-1 clients — OpenCode, Claude Code, Codex, and Cursor — have memory mining enabled by default. They have the most mature, stable, documented formats and are the ones most likely to contain the full interactive history you'd want to search.
|
|
2357
|
+
|
|
2358
|
+
For every other client, memory mining is **opt-in per runtime**. Enable it with:
|
|
2359
|
+
|
|
2360
|
+
```bash
|
|
2361
|
+
AIDEVOPS_FEATURE_MEMORY_GEMINI_CLI=yes setup.sh
|
|
2362
|
+
AIDEVOPS_FEATURE_MEMORY_CONTINUE=yes setup.sh
|
|
2363
|
+
```
|
|
2364
|
+
|
|
2365
|
+
**Privacy note.** Session files contain everything you typed — including secrets, credentials, and file contents pasted into prompts. The mining pipeline runs secretlint-style scrubbing at ingestion and defaults to local-only storage. Never sync the memory DB to a shared or cloud location without reviewing what's in it.
|
|
2366
|
+
|
|
2287
2367
|
See `.agents/memory/README.md` for complete documentation.
|
|
2288
2368
|
|
|
2289
2369
|
### **Installation**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.8.2
|
package/aidevops.sh
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
# SPDX-FileCopyrightText: 2025-2026 Marcus Quinn
|
|
2
4
|
|
|
3
5
|
# AI DevOps Framework CLI
|
|
4
6
|
# Usage: aidevops <command> [options]
|
|
5
7
|
#
|
|
6
|
-
# Version: 3.
|
|
8
|
+
# Version: 3.8.2
|
|
7
9
|
|
|
8
10
|
set -euo pipefail
|
|
9
11
|
|
|
@@ -502,17 +504,26 @@ check_protected_branch() {
|
|
|
502
504
|
repo_name=$(basename "$project_root")
|
|
503
505
|
local suggested_branch="$branch_type/$branch_suffix"
|
|
504
506
|
|
|
505
|
-
echo ""
|
|
506
|
-
print_warning "On protected branch '$current_branch'"
|
|
507
|
-
echo ""
|
|
508
|
-
echo "Options:"
|
|
509
|
-
echo " 1. Create worktree: $suggested_branch (recommended)"
|
|
510
|
-
echo " 2. Continue on $current_branch (commits directly to main)"
|
|
511
|
-
echo " 3. Cancel"
|
|
512
|
-
echo ""
|
|
513
507
|
local choice
|
|
514
|
-
|
|
515
|
-
|
|
508
|
+
# In non-interactive (non-TTY) contexts, auto-select option 1 (create worktree)
|
|
509
|
+
# without prompting. This prevents read from blocking or getting EOF in CI/AI
|
|
510
|
+
# assistant environments, which could cause silent script termination with set -e.
|
|
511
|
+
if [[ -t 0 ]]; then
|
|
512
|
+
echo ""
|
|
513
|
+
print_warning "On protected branch '$current_branch'"
|
|
514
|
+
echo ""
|
|
515
|
+
echo "Options:"
|
|
516
|
+
echo " 1. Create worktree: $suggested_branch (recommended)"
|
|
517
|
+
echo " 2. Continue on $current_branch (commits directly to main)"
|
|
518
|
+
echo " 3. Cancel"
|
|
519
|
+
echo ""
|
|
520
|
+
read -r -p "Choice [1]: " choice
|
|
521
|
+
choice="${choice:-1}"
|
|
522
|
+
else
|
|
523
|
+
# Non-interactive: auto-create worktree (safest default)
|
|
524
|
+
choice="1"
|
|
525
|
+
print_info "Non-interactive mode: auto-selecting worktree creation for '$suggested_branch'"
|
|
526
|
+
fi
|
|
516
527
|
|
|
517
528
|
case "$choice" in
|
|
518
529
|
1)
|
|
@@ -522,35 +533,34 @@ check_protected_branch() {
|
|
|
522
533
|
|
|
523
534
|
print_info "Creating worktree at $worktree_dir..."
|
|
524
535
|
|
|
536
|
+
local worktree_created=false
|
|
525
537
|
if [[ -f "$AGENTS_DIR/scripts/worktree-helper.sh" ]]; then
|
|
526
|
-
if bash "$AGENTS_DIR/scripts/worktree-helper.sh" add "$suggested_branch"
|
|
527
|
-
|
|
528
|
-
echo ""
|
|
529
|
-
print_success "Worktree created!"
|
|
530
|
-
print_info "Switching to: $worktree_dir"
|
|
531
|
-
echo ""
|
|
532
|
-
# Change to worktree directory
|
|
533
|
-
cd "$worktree_dir" || return 1
|
|
534
|
-
return 0
|
|
538
|
+
if bash "$AGENTS_DIR/scripts/worktree-helper.sh" add "$suggested_branch"; then
|
|
539
|
+
worktree_created=true
|
|
535
540
|
else
|
|
536
|
-
print_error "Failed to create worktree"
|
|
541
|
+
print_error "Failed to create worktree via worktree-helper.sh"
|
|
537
542
|
return 1
|
|
538
543
|
fi
|
|
539
544
|
else
|
|
540
545
|
# Fallback without helper script
|
|
541
|
-
if git worktree add -b "$suggested_branch" "$worktree_dir"
|
|
542
|
-
|
|
543
|
-
echo ""
|
|
544
|
-
print_success "Worktree created!"
|
|
545
|
-
print_info "Switching to: $worktree_dir"
|
|
546
|
-
echo ""
|
|
547
|
-
cd "$worktree_dir" || return 1
|
|
548
|
-
return 0
|
|
546
|
+
if git worktree add -b "$suggested_branch" "$worktree_dir"; then
|
|
547
|
+
worktree_created=true
|
|
549
548
|
else
|
|
550
549
|
print_error "Failed to create worktree"
|
|
551
550
|
return 1
|
|
552
551
|
fi
|
|
553
552
|
fi
|
|
553
|
+
|
|
554
|
+
if [[ "$worktree_created" == "true" ]]; then
|
|
555
|
+
export WORKTREE_PATH="$worktree_dir"
|
|
556
|
+
echo ""
|
|
557
|
+
print_success "Worktree created at: $worktree_dir"
|
|
558
|
+
print_info "Switching to: $worktree_dir"
|
|
559
|
+
echo ""
|
|
560
|
+
# Change to worktree directory for the remainder of this process
|
|
561
|
+
cd "$worktree_dir" || return 1
|
|
562
|
+
return 0
|
|
563
|
+
fi
|
|
554
564
|
;;
|
|
555
565
|
2)
|
|
556
566
|
print_warning "Continuing on $current_branch - changes will commit directly"
|
|
@@ -655,6 +665,22 @@ cmd_status() {
|
|
|
655
665
|
print_header "SSH Configuration"
|
|
656
666
|
check_file "$HOME/.ssh/id_ed25519" && print_success "Ed25519 SSH key" || print_warning "Ed25519 SSH key - not found"
|
|
657
667
|
echo ""
|
|
668
|
+
print_header "Commit Signing"
|
|
669
|
+
local signing_format signing_key signing_enabled
|
|
670
|
+
signing_format=$(git config --global gpg.format 2>/dev/null || echo "")
|
|
671
|
+
signing_key=$(git config --global user.signingkey 2>/dev/null || echo "")
|
|
672
|
+
signing_enabled=$(git config --global commit.gpgsign 2>/dev/null || echo "")
|
|
673
|
+
if [[ "$signing_format" == "ssh" && -n "$signing_key" && "$signing_enabled" == "true" ]]; then
|
|
674
|
+
print_success "SSH commit signing enabled"
|
|
675
|
+
if check_file "$HOME/.ssh/allowed_signers"; then
|
|
676
|
+
print_success "Allowed signers file configured"
|
|
677
|
+
else
|
|
678
|
+
print_warning "No allowed_signers file — run: aidevops signing setup"
|
|
679
|
+
fi
|
|
680
|
+
else
|
|
681
|
+
print_warning "Commit signing not configured — run: aidevops signing setup"
|
|
682
|
+
fi
|
|
683
|
+
echo ""
|
|
658
684
|
}
|
|
659
685
|
|
|
660
686
|
# Update helpers (extracted for complexity reduction)
|
|
@@ -838,6 +864,43 @@ _update_check_homebrew() {
|
|
|
838
864
|
return 0
|
|
839
865
|
}
|
|
840
866
|
|
|
867
|
+
# Verify supply chain signature after pulling framework updates.
|
|
868
|
+
# Checks that the HEAD commit is signed by the trusted maintainer key.
|
|
869
|
+
# Non-blocking: warns on failure, does not abort the update.
|
|
870
|
+
_update_verify_signature() {
|
|
871
|
+
local signing_helper="$AGENTS_DIR/scripts/signing-setup.sh"
|
|
872
|
+
|
|
873
|
+
# Cannot verify if the helper script is not yet deployed
|
|
874
|
+
if [[ ! -f "$signing_helper" ]]; then
|
|
875
|
+
return 0
|
|
876
|
+
fi
|
|
877
|
+
|
|
878
|
+
local result
|
|
879
|
+
result=$(bash "$signing_helper" verify-update "$INSTALL_DIR" 2>/dev/null || echo "UNKNOWN")
|
|
880
|
+
|
|
881
|
+
case "$result" in
|
|
882
|
+
VERIFIED)
|
|
883
|
+
print_success "Supply chain verified: HEAD commit is signed by trusted maintainer"
|
|
884
|
+
;;
|
|
885
|
+
UNSIGNED)
|
|
886
|
+
print_warning "HEAD commit is not signed — cannot verify supply chain integrity"
|
|
887
|
+
print_info "This is expected for older releases. Signed commits start from v3.6.21+"
|
|
888
|
+
;;
|
|
889
|
+
UNTRUSTED)
|
|
890
|
+
print_warning "HEAD commit is signed but by an untrusted key"
|
|
891
|
+
print_info "Run 'aidevops signing setup' to configure signature verification"
|
|
892
|
+
;;
|
|
893
|
+
BAD_SIGNATURE)
|
|
894
|
+
print_error "HEAD commit has a BAD signature — update may be compromised"
|
|
895
|
+
print_info "Verify manually: cd $INSTALL_DIR && git log --show-signature -1"
|
|
896
|
+
;;
|
|
897
|
+
UNVERIFIABLE)
|
|
898
|
+
# Signing not configured yet — silent, do not nag
|
|
899
|
+
;;
|
|
900
|
+
esac
|
|
901
|
+
return 0
|
|
902
|
+
}
|
|
903
|
+
|
|
841
904
|
# Update/upgrade command
|
|
842
905
|
cmd_update() {
|
|
843
906
|
local skip_project_sync=false
|
|
@@ -907,6 +970,9 @@ cmd_update() {
|
|
|
907
970
|
fi
|
|
908
971
|
fi
|
|
909
972
|
echo ""
|
|
973
|
+
# Verify supply chain integrity before applying changes
|
|
974
|
+
_update_verify_signature
|
|
975
|
+
echo ""
|
|
910
976
|
print_info "Running setup to apply changes..."
|
|
911
977
|
local setup_exit=0
|
|
912
978
|
bash "$INSTALL_DIR/setup.sh" --non-interactive || setup_exit=$?
|
|
@@ -1427,6 +1493,61 @@ EOF
|
|
|
1427
1493
|
return 0
|
|
1428
1494
|
}
|
|
1429
1495
|
|
|
1496
|
+
# Scaffold .agents/commands/ and .windsurf/workflows/ symlinks so that clients
|
|
1497
|
+
# which read repo-local command directories (Amp reads .agents/commands/ natively;
|
|
1498
|
+
# Windsurf reads .windsurf/workflows/) see the aidevops main-agent slash commands.
|
|
1499
|
+
#
|
|
1500
|
+
# Behavior is idempotent:
|
|
1501
|
+
# - If .agents/commands/ already contains the expected aidevops-*.md symlinks
|
|
1502
|
+
# (this repo IS the aidevops source), do nothing.
|
|
1503
|
+
# - Otherwise link .agents/commands/ → ~/.aidevops/agents/commands/
|
|
1504
|
+
# - Always link .windsurf/workflows/ → ../.agents/commands/ (relative)
|
|
1505
|
+
_init_scaffold_commands_symlinks() {
|
|
1506
|
+
local project_root="$1"
|
|
1507
|
+
local source_dir="$HOME/.aidevops/agents/commands"
|
|
1508
|
+
local commands_dir="$project_root/.agents/commands"
|
|
1509
|
+
local windsurf_dir="$project_root/.windsurf"
|
|
1510
|
+
local workflows_link="$windsurf_dir/workflows"
|
|
1511
|
+
|
|
1512
|
+
# If .agents/commands/ already contains main-agent symlinks, this repo
|
|
1513
|
+
# manages them directly (e.g. the aidevops source repo itself) — leave
|
|
1514
|
+
# it alone so we never overwrite authoritative content.
|
|
1515
|
+
if [[ -e "$commands_dir/aidevops-build-plus.md" ]]; then
|
|
1516
|
+
print_info ".agents/commands/ already contains main-agent symlinks — preserving"
|
|
1517
|
+
elif [[ ! -d "$source_dir" ]]; then
|
|
1518
|
+
print_warning "Framework commands dir not found at $source_dir — run setup.sh first to deploy main-agent symlinks"
|
|
1519
|
+
elif [[ -L "$commands_dir" ]]; then
|
|
1520
|
+
# Existing symlink — point at the canonical source
|
|
1521
|
+
local current_target
|
|
1522
|
+
current_target=$(readlink "$commands_dir")
|
|
1523
|
+
if [[ "$current_target" != "$source_dir" ]]; then
|
|
1524
|
+
rm "$commands_dir"
|
|
1525
|
+
ln -s "$source_dir" "$commands_dir"
|
|
1526
|
+
print_success "Re-linked .agents/commands/ → $source_dir"
|
|
1527
|
+
else
|
|
1528
|
+
print_info ".agents/commands/ already linked correctly"
|
|
1529
|
+
fi
|
|
1530
|
+
elif [[ -d "$commands_dir" ]]; then
|
|
1531
|
+
print_warning ".agents/commands/ exists as a real directory — not overwriting"
|
|
1532
|
+
else
|
|
1533
|
+
ln -s "$source_dir" "$commands_dir"
|
|
1534
|
+
print_success "Linked .agents/commands/ → $source_dir (Amp reads this natively)"
|
|
1535
|
+
fi
|
|
1536
|
+
|
|
1537
|
+
# .windsurf/workflows/ → ../.agents/commands/ (relative, so the link
|
|
1538
|
+
# resolves inside the repo regardless of checkout path).
|
|
1539
|
+
mkdir -p "$windsurf_dir"
|
|
1540
|
+
if [[ -L "$workflows_link" ]]; then
|
|
1541
|
+
print_info ".windsurf/workflows/ already linked"
|
|
1542
|
+
elif [[ -d "$workflows_link" ]]; then
|
|
1543
|
+
print_warning ".windsurf/workflows/ exists as a real directory — not overwriting"
|
|
1544
|
+
else
|
|
1545
|
+
(cd "$windsurf_dir" && ln -s "../.agents/commands" workflows)
|
|
1546
|
+
print_success "Linked .windsurf/workflows/ → ../.agents/commands (Windsurf slash commands)"
|
|
1547
|
+
fi
|
|
1548
|
+
return 0
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1430
1551
|
# Init command - initialize aidevops in a project
|
|
1431
1552
|
cmd_init() {
|
|
1432
1553
|
local features="${1:-all}"
|
|
@@ -1570,6 +1691,10 @@ EOF
|
|
|
1570
1691
|
print_success "Created .agents/ directory"
|
|
1571
1692
|
fi
|
|
1572
1693
|
|
|
1694
|
+
# Link .agents/commands/ and .windsurf/workflows/ so Amp (native) and Windsurf
|
|
1695
|
+
# (symlinked) can see the aidevops main-agent slash commands.
|
|
1696
|
+
_init_scaffold_commands_symlinks "$project_root"
|
|
1697
|
+
|
|
1573
1698
|
# Scaffold or update .agents/AGENTS.md (idempotent — creates if missing,
|
|
1574
1699
|
# updates Security section if file already exists)
|
|
1575
1700
|
local _agents_md_existed=false
|
|
@@ -1966,6 +2091,18 @@ GITATTRSEOF
|
|
|
1966
2091
|
print_info "Collaborator pointer files already exist"
|
|
1967
2092
|
fi
|
|
1968
2093
|
|
|
2094
|
+
# Seed DESIGN.md template (AI-readable design system skeleton)
|
|
2095
|
+
if [[ ! -f "$project_root/DESIGN.md" ]]; then
|
|
2096
|
+
local design_template="$AGENTS_DIR/templates/DESIGN.md.template"
|
|
2097
|
+
if [[ -f "$design_template" ]]; then
|
|
2098
|
+
# Replace {Project Name} with the repo name
|
|
2099
|
+
sed "s/{Project Name}/$repo_name/g" "$design_template" >"$project_root/DESIGN.md"
|
|
2100
|
+
print_success "Created DESIGN.md (design system skeleton — populate with tools/design/design-md.md)"
|
|
2101
|
+
fi
|
|
2102
|
+
else
|
|
2103
|
+
print_info "DESIGN.md already exists, skipping"
|
|
2104
|
+
fi
|
|
2105
|
+
|
|
1969
2106
|
# Scaffold repo courtesy files (README, LICENCE, CHANGELOG, etc.)
|
|
1970
2107
|
scaffold_repo_courtesy_files "$project_root"
|
|
1971
2108
|
|
|
@@ -2009,8 +2146,21 @@ GITATTRSEOF
|
|
|
2009
2146
|
[[ "$enable_security" == "true" ]] && features_list="${features_list}security,"
|
|
2010
2147
|
features_list="${features_list%,}" # Remove trailing comma
|
|
2011
2148
|
|
|
2012
|
-
# Register repo in repos.json
|
|
2013
|
-
|
|
2149
|
+
# Register the *main* repo path (not the worktree path) in repos.json.
|
|
2150
|
+
# When check_protected_branch creates a worktree and cd's into it,
|
|
2151
|
+
# $project_root (resolved via git rev-parse --show-toplevel) points to the
|
|
2152
|
+
# worktree directory. We must register the canonical main worktree path so
|
|
2153
|
+
# that pulse and cleanup processes don't treat the worktree as a standalone repo.
|
|
2154
|
+
local register_path="$project_root"
|
|
2155
|
+
if [[ -n "${WORKTREE_PATH:-}" ]]; then
|
|
2156
|
+
# We're inside a worktree — resolve the main worktree path from git metadata
|
|
2157
|
+
local main_wt_path
|
|
2158
|
+
main_wt_path=$(git -C "$project_root" worktree list --porcelain 2>/dev/null | awk '/^worktree /{print $2; exit}')
|
|
2159
|
+
if [[ -n "$main_wt_path" ]] && [[ "$main_wt_path" != "$project_root" ]]; then
|
|
2160
|
+
register_path="$main_wt_path"
|
|
2161
|
+
fi
|
|
2162
|
+
fi
|
|
2163
|
+
register_repo "$register_path" "$aidevops_version" "$features_list"
|
|
2014
2164
|
|
|
2015
2165
|
# Auto-commit initialized files so they don't linger as mystery unstaged
|
|
2016
2166
|
# changes (#2570 bug 2). Collect all files that cmd_init creates/modifies.
|
|
@@ -2019,6 +2169,7 @@ GITATTRSEOF
|
|
|
2019
2169
|
[[ -f "$project_root/.gitignore" ]] && init_files+=(".gitignore")
|
|
2020
2170
|
[[ -d "$project_root/.agents" ]] && init_files+=(".agents/")
|
|
2021
2171
|
[[ -f "$project_root/AGENTS.md" ]] && init_files+=("AGENTS.md")
|
|
2172
|
+
[[ -f "$project_root/DESIGN.md" ]] && init_files+=("DESIGN.md")
|
|
2022
2173
|
[[ -f "$project_root/TODO.md" ]] && init_files+=("TODO.md")
|
|
2023
2174
|
[[ -d "$project_root/todo" ]] && init_files+=("todo/")
|
|
2024
2175
|
[[ -f "$project_root/MODELS.md" ]] && init_files+=("MODELS.md")
|
|
@@ -2064,6 +2215,22 @@ GITATTRSEOF
|
|
|
2064
2215
|
[[ "$enable_security" == "true" ]] && echo " ✓ Security (per-repo posture assessment)"
|
|
2065
2216
|
[[ -f "$project_root/MODELS.md" ]] && echo " ✓ MODELS.md (per-repo model performance leaderboard)"
|
|
2066
2217
|
echo ""
|
|
2218
|
+
# When init ran inside a worktree (check_protected_branch created one),
|
|
2219
|
+
# print explicit instructions so the user knows where to find their work.
|
|
2220
|
+
# Without this, the user's shell is back in the main repo after aidevops exits
|
|
2221
|
+
# and the worktree appears to have "disappeared".
|
|
2222
|
+
if [[ -n "${WORKTREE_PATH:-}" ]]; then
|
|
2223
|
+
local worktree_branch
|
|
2224
|
+
worktree_branch=$(git branch --show-current 2>/dev/null || echo "chore/aidevops-init")
|
|
2225
|
+
echo "Worktree location:"
|
|
2226
|
+
echo " $WORKTREE_PATH"
|
|
2227
|
+
echo ""
|
|
2228
|
+
echo "Your init commit is in the worktree above. To continue:"
|
|
2229
|
+
echo " cd $WORKTREE_PATH"
|
|
2230
|
+
echo " git push -u origin ${worktree_branch}"
|
|
2231
|
+
echo " gh pr create --fill"
|
|
2232
|
+
echo ""
|
|
2233
|
+
fi
|
|
2067
2234
|
echo "Next steps:"
|
|
2068
2235
|
local step=1
|
|
2069
2236
|
if [[ "$committed" != "true" ]]; then
|
|
@@ -2157,7 +2324,39 @@ _upgrade_todo() {
|
|
|
2157
2324
|
print_info "Upgrading TODO.md..."
|
|
2158
2325
|
local existing_tasks=""
|
|
2159
2326
|
if [[ -f "$todo_file" ]]; then
|
|
2160
|
-
|
|
2327
|
+
# Extract everything under ## Backlog (tasks AND ### subsection headers)
|
|
2328
|
+
# until the next ## header or EOF — preserves semantic grouping.
|
|
2329
|
+
# GH#17804: Skip ## Format section and filter out template placeholder IDs
|
|
2330
|
+
# (tXXX, tYYY, tZZZ) that are documentation examples, not real tasks.
|
|
2331
|
+
existing_tasks=$(awk '
|
|
2332
|
+
# Section-aware: track when inside ## Format to skip its content
|
|
2333
|
+
/^## Format/ { in_format=1; next }
|
|
2334
|
+
in_format && /^## / { in_format=0 }
|
|
2335
|
+
in_format { next }
|
|
2336
|
+
# Also skip content inside markdown code blocks (``` fenced blocks)
|
|
2337
|
+
/^```/ { in_codeblock = !in_codeblock; next }
|
|
2338
|
+
in_codeblock { next }
|
|
2339
|
+
# Extract from ## Backlog to next ## header
|
|
2340
|
+
/^## Backlog/ { found=1; next }
|
|
2341
|
+
found && /^## / { exit }
|
|
2342
|
+
found
|
|
2343
|
+
' "$todo_file" 2>/dev/null || echo "")
|
|
2344
|
+
# GH#17804: Filter out lines with non-numeric task IDs (template placeholders
|
|
2345
|
+
# like tXXX, tYYY, tZZZ). Real task IDs match t<digits> or t<digits>.<digits>.
|
|
2346
|
+
if [[ -n "$existing_tasks" ]]; then
|
|
2347
|
+
existing_tasks=$(printf '%s\n' "$existing_tasks" | awk '
|
|
2348
|
+
# Keep non-task lines (subsection headers, comments, blank lines)
|
|
2349
|
+
!/^- \[[ x-]\] t/ { print; next }
|
|
2350
|
+
# For task lines: extract the ID and validate it is numeric
|
|
2351
|
+
{
|
|
2352
|
+
id = $0
|
|
2353
|
+
sub(/^- \[[ x-]\] /, "", id)
|
|
2354
|
+
sub(/ .*/, "", id)
|
|
2355
|
+
# Valid IDs: t followed by digits, optionally .digits (subtasks)
|
|
2356
|
+
if (id ~ /^t[0-9]+(\.[0-9]+)*$/) print
|
|
2357
|
+
}
|
|
2358
|
+
')
|
|
2359
|
+
fi
|
|
2161
2360
|
[[ "$backup" == "true" ]] && {
|
|
2162
2361
|
cp "$todo_file" "${todo_file}.bak"
|
|
2163
2362
|
print_success "Backup created: TODO.md.bak"
|
|
@@ -3279,6 +3478,7 @@ cmd_skills() {
|
|
|
3279
3478
|
_help_commands() {
|
|
3280
3479
|
echo "Commands:"
|
|
3281
3480
|
echo " init [features] Initialize aidevops in current project"
|
|
3481
|
+
echo " init-routines Scaffold private routines repo (--org <name> | --local)"
|
|
3282
3482
|
echo " upgrade-planning Upgrade TODO.md/PLANS.md to latest templates"
|
|
3283
3483
|
echo " features List available features for init"
|
|
3284
3484
|
echo " skill <cmd> Manage agent skills (add/list/check/update/remove)"
|
|
@@ -3293,8 +3493,10 @@ _help_commands() {
|
|
|
3293
3493
|
echo " repo-sync <cmd> Daily git pull for repos in parent dirs (enable/disable/status/dirs)"
|
|
3294
3494
|
echo " update-tools Check for outdated tools (--update to auto-update)"
|
|
3295
3495
|
echo " repos [cmd] Manage registered projects (list/add/remove/clean)"
|
|
3296
|
-
echo " model-accounts-pool OAuth account pool (list/check/add/rotate/reset-cooldowns)"
|
|
3496
|
+
echo " model-accounts-pool OAuth account pool (list/check/diagnose/add/rotate/reset-cooldowns)"
|
|
3497
|
+
echo " client-format Client request format alignment (extract/check/canary/monitor)"
|
|
3297
3498
|
echo " opencode-sandbox Test OpenCode versions in isolation (install/run/check/clean)"
|
|
3499
|
+
echo " approve <cmd> Cryptographic issue/PR approval (setup/issue/pr/verify/status)"
|
|
3298
3500
|
echo " security [cmd] Full security assessment (posture + hygiene + supply chain)"
|
|
3299
3501
|
echo " ip-check <cmd> IP reputation checks (check/batch/report/providers)"
|
|
3300
3502
|
echo " secret <cmd> Manage secrets (set/list/run/init/import/status)"
|
|
@@ -3331,6 +3533,7 @@ _help_detailed_sections() {
|
|
|
3331
3533
|
echo " aidevops model-accounts-pool status # Pool health at a glance"
|
|
3332
3534
|
echo " aidevops model-accounts-pool list # Per-account detail"
|
|
3333
3535
|
echo " aidevops model-accounts-pool check # Live token validity test"
|
|
3536
|
+
echo " aidevops model-accounts-pool diagnose # Full pipeline diagnostics (pool, plugin, CCH, runtime)"
|
|
3334
3537
|
echo " aidevops model-accounts-pool rotate [provider] # Switch to next available account NOW (use when rate-limited)"
|
|
3335
3538
|
echo " aidevops model-accounts-pool reset-cooldowns # Clear rate-limit cooldowns"
|
|
3336
3539
|
echo " aidevops model-accounts-pool add anthropic # Add Claude Pro/Max account"
|
|
@@ -3341,13 +3544,26 @@ _help_detailed_sections() {
|
|
|
3341
3544
|
echo " aidevops model-accounts-pool assign-pending <provider># Assign stranded token"
|
|
3342
3545
|
echo " aidevops model-accounts-pool remove <provider> <email># Remove an account"
|
|
3343
3546
|
echo ""
|
|
3344
|
-
echo " Auth
|
|
3547
|
+
echo " Auth troubleshooting (run diagnose first, then recovery if needed):"
|
|
3548
|
+
echo " aidevops model-accounts-pool diagnose # 0. Full pipeline check (start here)"
|
|
3345
3549
|
echo " aidevops model-accounts-pool status # 1. Check pool health"
|
|
3346
3550
|
echo " aidevops model-accounts-pool check # 2. Test token validity"
|
|
3347
3551
|
echo " aidevops model-accounts-pool rotate anthropic# 3. Switch account if rate-limited"
|
|
3348
3552
|
echo " aidevops model-accounts-pool reset-cooldowns # 4. Clear cooldowns if all stuck"
|
|
3349
3553
|
echo " aidevops model-accounts-pool add anthropic # 5. Re-add if pool empty"
|
|
3350
3554
|
echo ""
|
|
3555
|
+
echo "Client Format:"
|
|
3556
|
+
echo " aidevops client-format # Show status + cached constants"
|
|
3557
|
+
echo " aidevops client-format extract # Re-extract constants from installed CLI"
|
|
3558
|
+
echo " aidevops client-format check # Verify cache matches installed CLI version"
|
|
3559
|
+
echo " aidevops client-format canary # Run drift check against real CLI (uses tokens)"
|
|
3560
|
+
echo " aidevops client-format monitor [cmd] # Traffic capture + diff (requires mitmproxy)"
|
|
3561
|
+
echo " aidevops client-format install-canary # Install daily drift check (launchd)"
|
|
3562
|
+
echo ""
|
|
3563
|
+
echo " If requests stop working after a CLI update:"
|
|
3564
|
+
echo " aidevops client-format extract # 1. Re-extract constants"
|
|
3565
|
+
echo " aidevops client-format canary # 2. Verify against real CLI"
|
|
3566
|
+
echo ""
|
|
3351
3567
|
echo "Secrets:"
|
|
3352
3568
|
echo " aidevops secret set NAME # Store a secret (hidden input)"
|
|
3353
3569
|
echo " aidevops secret list # List secret names (never values)"
|
|
@@ -3585,10 +3801,53 @@ main() {
|
|
|
3585
3801
|
detect | scan) cmd_detect ;;
|
|
3586
3802
|
ip-check | ip_check) _dispatch_helper "ip-reputation-helper.sh" "ip-reputation-helper.sh" "$@" ;;
|
|
3587
3803
|
model-accounts-pool | map) _dispatch_helper "oauth-pool-helper.sh" "oauth-pool-helper.sh" "$@" ;;
|
|
3804
|
+
client-format)
|
|
3805
|
+
case "${1:-status}" in
|
|
3806
|
+
extract | refresh)
|
|
3807
|
+
_dispatch_helper "cch-extract.sh" "cch-extract.sh" --cache
|
|
3808
|
+
;;
|
|
3809
|
+
check | verify)
|
|
3810
|
+
_dispatch_helper "cch-extract.sh" "cch-extract.sh" --verify
|
|
3811
|
+
;;
|
|
3812
|
+
canary | test)
|
|
3813
|
+
shift || true
|
|
3814
|
+
_dispatch_helper "cch-canary.sh" "cch-canary.sh" --verbose "$@"
|
|
3815
|
+
;;
|
|
3816
|
+
monitor)
|
|
3817
|
+
shift || true
|
|
3818
|
+
_dispatch_helper "cch-traffic-monitor.sh" "cch-traffic-monitor.sh" "$@"
|
|
3819
|
+
;;
|
|
3820
|
+
install-canary)
|
|
3821
|
+
_dispatch_helper "cch-canary.sh" "cch-canary.sh" --install
|
|
3822
|
+
;;
|
|
3823
|
+
status | "")
|
|
3824
|
+
echo ""
|
|
3825
|
+
echo "Client request format alignment"
|
|
3826
|
+
echo "==============================="
|
|
3827
|
+
echo ""
|
|
3828
|
+
_dispatch_helper "cch-extract.sh" "cch-extract.sh" --verify 2>&1 || true
|
|
3829
|
+
echo ""
|
|
3830
|
+
if [[ -f "$HOME/.aidevops/cch-constants.json" ]]; then
|
|
3831
|
+
echo "Cached constants:"
|
|
3832
|
+
cat "$HOME/.aidevops/cch-constants.json"
|
|
3833
|
+
else
|
|
3834
|
+
echo "No cached constants. Run: aidevops client-format extract"
|
|
3835
|
+
fi
|
|
3836
|
+
;;
|
|
3837
|
+
*)
|
|
3838
|
+
print_error "Unknown subcommand: $1"
|
|
3839
|
+
echo "Usage: aidevops client-format [extract|check|canary|monitor|install-canary|status]"
|
|
3840
|
+
exit 1
|
|
3841
|
+
;;
|
|
3842
|
+
esac
|
|
3843
|
+
;;
|
|
3588
3844
|
opencode-sandbox | oc-sandbox) _dispatch_helper "opencode-sandbox-helper.sh" "opencode-sandbox-helper.sh" "$@" ;;
|
|
3589
3845
|
secret | secrets) _dispatch_helper "secret-helper.sh" "secret-helper.sh" "$@" ;;
|
|
3846
|
+
approve) _dispatch_helper "approval-helper.sh" "approval-helper.sh" "$@" ;;
|
|
3847
|
+
signing) _dispatch_helper "signing-setup.sh" "signing-setup.sh" "$@" ;;
|
|
3590
3848
|
stats | observability) _dispatch_helper "observability-helper.sh" "observability-helper.sh" "$@" ;;
|
|
3591
3849
|
tabby) _dispatch_helper "tabby-helper.sh" "tabby-helper.sh" "$@" ;;
|
|
3850
|
+
init-routines) _dispatch_helper "init-routines-helper.sh" "init-routines-helper.sh" "$@" ;;
|
|
3592
3851
|
config | configure) _dispatch_config "$@" ;;
|
|
3593
3852
|
uninstall | remove) cmd_uninstall ;;
|
|
3594
3853
|
version | v | -v | --version) cmd_version ;;
|