@waoooo/claude-skills 1.0.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/README.md +48 -0
- package/package.json +28 -0
- package/registry.json +431 -0
- package/skills/acceptance-review/SKILL.md +537 -0
- package/skills/all-plan/SKILL.md +19 -0
- package/skills/all-plan/references/flow.md +750 -0
- package/skills/api-docs-generate/SKILL.md +204 -0
- package/skills/api-docs-generate/assets/templates/api.mdx +140 -0
- package/skills/api-docs-generate/scripts/generate-api-docs.ts +308 -0
- package/skills/ask/SKILL.md +42 -0
- package/skills/autonew/SKILL.md +34 -0
- package/skills/capability-analyze/SKILL.md +300 -0
- package/skills/capability-analyze/scripts/analyze-capabilities.ts +531 -0
- package/skills/capability-docs-generate/SKILL.md +155 -0
- package/skills/capability-docs-generate/assets/templates/capability.mdx +271 -0
- package/skills/capability-docs-generate/scripts/generate-capability-docs.ts +358 -0
- package/skills/capability-tree-query/SKILL.md +112 -0
- package/skills/capability-tree-query/scripts/build-capability-tree.ts +402 -0
- package/skills/changelog-generator/SKILL.md +104 -0
- package/skills/continue/SKILL.md +39 -0
- package/skills/continue/agents/openai.yaml +3 -0
- package/skills/creating-skills/SKILL.md +158 -0
- package/skills/creating-skills/references/official_best_practices.md +128 -0
- package/skills/creating-skills/references/skill_examples.md +199 -0
- package/skills/docx/LICENSE.txt +30 -0
- package/skills/docx/SKILL.md +197 -0
- package/skills/docx/docx-js.md +350 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/skills/docx/ooxml/schemas/mce/mc.xsd +75 -0
- package/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/skills/docx/ooxml/scripts/pack.py +159 -0
- package/skills/docx/ooxml/scripts/unpack.py +29 -0
- package/skills/docx/ooxml/scripts/validate.py +69 -0
- package/skills/docx/ooxml/scripts/validation/__init__.py +15 -0
- package/skills/docx/ooxml/scripts/validation/base.py +951 -0
- package/skills/docx/ooxml/scripts/validation/docx.py +274 -0
- package/skills/docx/ooxml/scripts/validation/pptx.py +315 -0
- package/skills/docx/ooxml/scripts/validation/redlining.py +279 -0
- package/skills/docx/ooxml.md +610 -0
- package/skills/docx/scripts/__init__.py +1 -0
- package/skills/docx/scripts/document.py +1276 -0
- package/skills/docx/scripts/templates/comments.xml +3 -0
- package/skills/docx/scripts/templates/commentsExtended.xml +3 -0
- package/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
- package/skills/docx/scripts/templates/commentsIds.xml +3 -0
- package/skills/docx/scripts/templates/people.xml +3 -0
- package/skills/docx/scripts/utilities.py +374 -0
- package/skills/git-branch-create/SKILL.md +170 -0
- package/skills/git-branch-merge/SKILL.md +176 -0
- package/skills/git-commit/SKILL.md +56 -0
- package/skills/git-commit/references/commit_examples.md +311 -0
- package/skills/github-actions-trigger/SKILL.md +367 -0
- package/skills/github-issue-create/SKILL.md +294 -0
- package/skills/github-pr-creation/SKILL.md +137 -0
- package/skills/github-pr-creation/references/pr_templates.md +187 -0
- package/skills/github-pr-merge/SKILL.md +112 -0
- package/skills/github-pr-review/SKILL.md +110 -0
- package/skills/github-pr-review/references/severity_guide.md +168 -0
- package/skills/job-create/SKILL.md +294 -0
- package/skills/job-create/scripts/create-job.ts +105 -0
- package/skills/job-workflow/SKILL.md +212 -0
- package/skills/keyword-extract/SKILL.md +229 -0
- package/skills/mcp-builder/LICENSE.txt +202 -0
- package/skills/mcp-builder/SKILL.md +236 -0
- package/skills/mcp-builder/reference/evaluation.md +602 -0
- package/skills/mcp-builder/reference/mcp_best_practices.md +249 -0
- package/skills/mcp-builder/reference/node_mcp_server.md +970 -0
- package/skills/mcp-builder/reference/python_mcp_server.md +719 -0
- package/skills/mcp-builder/scripts/connections.py +151 -0
- package/skills/mcp-builder/scripts/evaluation.py +373 -0
- package/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
- package/skills/mcp-builder/scripts/requirements.txt +2 -0
- package/skills/mdx-to-openspec/SKILL.md +827 -0
- package/skills/mdx-to-openspec/scripts/mdx-to-openspec.ts +320 -0
- package/skills/mounted/SKILL.md +20 -0
- package/skills/multi-model-review/SKILL.md +459 -0
- package/skills/notion-automation/SKILL.md +215 -0
- package/skills/openspec-review/SKILL.md +513 -0
- package/skills/pdf/LICENSE.txt +30 -0
- package/skills/pdf/SKILL.md +294 -0
- package/skills/pdf/forms.md +205 -0
- package/skills/pdf/reference.md +612 -0
- package/skills/pdf/scripts/check_bounding_boxes.py +70 -0
- package/skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
- package/skills/pdf/scripts/check_fillable_fields.py +12 -0
- package/skills/pdf/scripts/convert_pdf_to_images.py +35 -0
- package/skills/pdf/scripts/create_validation_image.py +41 -0
- package/skills/pdf/scripts/extract_form_field_info.py +152 -0
- package/skills/pdf/scripts/fill_fillable_fields.py +114 -0
- package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
- package/skills/pend/SKILL.md +33 -0
- package/skills/ping/SKILL.md +39 -0
- package/skills/pptx/LICENSE.txt +30 -0
- package/skills/pptx/SKILL.md +484 -0
- package/skills/pptx/html2pptx.md +625 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/skills/pptx/ooxml/schemas/mce/mc.xsd +75 -0
- package/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/skills/pptx/ooxml/scripts/pack.py +159 -0
- package/skills/pptx/ooxml/scripts/unpack.py +29 -0
- package/skills/pptx/ooxml/scripts/validate.py +69 -0
- package/skills/pptx/ooxml/scripts/validation/__init__.py +15 -0
- package/skills/pptx/ooxml/scripts/validation/base.py +951 -0
- package/skills/pptx/ooxml/scripts/validation/docx.py +274 -0
- package/skills/pptx/ooxml/scripts/validation/pptx.py +315 -0
- package/skills/pptx/ooxml/scripts/validation/redlining.py +279 -0
- package/skills/pptx/ooxml.md +427 -0
- package/skills/pptx/scripts/html2pptx.js +979 -0
- package/skills/pptx/scripts/inventory.py +1020 -0
- package/skills/pptx/scripts/rearrange.py +231 -0
- package/skills/pptx/scripts/replace.py +385 -0
- package/skills/pptx/scripts/thumbnail.py +450 -0
- package/skills/progress-update/SKILL.md +394 -0
- package/skills/progress-update/scripts/update-progress.ts +221 -0
- package/skills/release-automation/SKILL.md +306 -0
- package/skills/requirement-parse/SKILL.md +212 -0
- package/skills/requirement-parse/scripts/infer-builder-config.ts +346 -0
- package/skills/requirement-parse/scripts/merge-requirements.ts +228 -0
- package/skills/requirement-parse/scripts/parse-docs.ts +206 -0
- package/skills/requirement-parse/scripts/parse-openspec.ts +168 -0
- package/skills/roadmap-docs-generate/SKILL.md +483 -0
- package/skills/roadmap-docs-generate/assets/templates/ROADMAP.mdx +75 -0
- package/skills/roadmap-docs-generate/assets/templates/ROADMAP.mdx.template +330 -0
- package/skills/roadmap-docs-generate/assets/templates/TODO.mdx +56 -0
- package/skills/roadmap-docs-generate/assets/templates/TODO.mdx.template +363 -0
- package/skills/roadmap-docs-generate/scripts/json-to-mdx.ts +445 -0
- package/skills/roadmap-docs-generate/scripts/json-to-mdx.ts.backup +411 -0
- package/skills/roadmap-generate/SKILL.md +396 -0
- package/skills/roadmap-generate/scripts/generate-roadmap.ts +496 -0
- package/skills/skill-creator/LICENSE.txt +202 -0
- package/skills/skill-creator/SKILL.md +356 -0
- package/skills/skill-creator/references/output-patterns.md +82 -0
- package/skills/skill-creator/references/workflows.md +28 -0
- package/skills/skill-creator/scripts/init_skill.py +303 -0
- package/skills/skill-creator/scripts/package_skill.py +110 -0
- package/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/skills/spec-generate/SKILL.md +408 -0
- package/skills/spec-generate/scripts/generate-specs.ts +538 -0
- package/skills/spec-generate/scripts/generate-tasks.ts +174 -0
- package/skills/specs-review/SKILL.md +370 -0
- package/skills/task-execute/SKILL.md +399 -0
- package/skills/task-update-status/SKILL.md +349 -0
- package/skills/task-update-status/scripts/update-task-status.ts +192 -0
- package/skills/task-verify/SKILL.md +407 -0
- package/skills/ui-ux-pro-max/SKILL.md +386 -0
- package/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/skills/ui-ux-pro-max/data/styles.csv +68 -0
- package/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/skills/ui-ux-pro-max/scripts/core.py +253 -0
- package/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/skills/ui-ux-pro-max/scripts/search.py +114 -0
- package/skills/vercel-automation/SKILL.md +226 -0
- package/skills/webapp-testing/LICENSE.txt +202 -0
- package/skills/webapp-testing/SKILL.md +96 -0
- package/skills/webapp-testing/examples/console_logging.py +35 -0
- package/skills/webapp-testing/examples/element_discovery.py +40 -0
- package/skills/webapp-testing/examples/static_html_automation.py +33 -0
- package/skills/webapp-testing/scripts/with_server.py +106 -0
- package/skills/worktree-manager/SKILL.md +725 -0
- package/skills/worktree-manager/config.json +15 -0
- package/skills/worktree-manager/scripts/allocate-ports.sh +100 -0
- package/skills/worktree-manager/scripts/cleanup.sh +185 -0
- package/skills/worktree-manager/scripts/launch-agent.sh +155 -0
- package/skills/worktree-manager/scripts/register.sh +125 -0
- package/skills/worktree-manager/scripts/release-ports.sh +48 -0
- package/skills/worktree-manager/scripts/status.sh +169 -0
- package/skills/worktree-manager/scripts/sync.sh +168 -0
- package/skills/worktree-manager/templates/worktree.json +23 -0
- package/skills/xlsx/LICENSE.txt +30 -0
- package/skills/xlsx/SKILL.md +289 -0
- package/skills/xlsx/recalc.py +178 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"terminal": "ghostty",
|
|
3
|
+
"shell": "fish",
|
|
4
|
+
"claudeCommand": "cc",
|
|
5
|
+
"portPool": {
|
|
6
|
+
"start": 8100,
|
|
7
|
+
"end": 8199
|
|
8
|
+
},
|
|
9
|
+
"portsPerWorktree": 2,
|
|
10
|
+
"worktreeBase": "~/.archon/worktrees",
|
|
11
|
+
"registryPath": "~/.claude/worktree-registry.json",
|
|
12
|
+
"defaultCopyDirs": [".agents", ".env.example", ".env"],
|
|
13
|
+
"healthCheckTimeout": 30,
|
|
14
|
+
"healthCheckRetries": 6
|
|
15
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# allocate-ports.sh - Allocate N unused ports from global pool
|
|
3
|
+
#
|
|
4
|
+
# Usage: ./allocate-ports.sh <count>
|
|
5
|
+
#
|
|
6
|
+
# Returns: Space-separated list of port numbers
|
|
7
|
+
# Example: ./allocate-ports.sh 2 → "8100 8101"
|
|
8
|
+
#
|
|
9
|
+
# Also updates the registry to mark ports as allocated
|
|
10
|
+
|
|
11
|
+
set -e
|
|
12
|
+
|
|
13
|
+
COUNT="${1:-2}"
|
|
14
|
+
|
|
15
|
+
# Validate input
|
|
16
|
+
if ! [[ "$COUNT" =~ ^[0-9]+$ ]] || [ "$COUNT" -lt 1 ]; then
|
|
17
|
+
echo "Error: Count must be a positive integer" >&2
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
# Find config and registry
|
|
22
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
23
|
+
CONFIG_FILE="$SCRIPT_DIR/../config.json"
|
|
24
|
+
REGISTRY="${HOME}/.claude/worktree-registry.json"
|
|
25
|
+
|
|
26
|
+
# Load port pool from config
|
|
27
|
+
if [ -f "$CONFIG_FILE" ] && command -v jq &> /dev/null; then
|
|
28
|
+
PORT_START=$(jq -r '.portPool.start // 8100' "$CONFIG_FILE")
|
|
29
|
+
PORT_END=$(jq -r '.portPool.end // 8199' "$CONFIG_FILE")
|
|
30
|
+
else
|
|
31
|
+
PORT_START=8100
|
|
32
|
+
PORT_END=8199
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# Check jq is available
|
|
36
|
+
if ! command -v jq &> /dev/null; then
|
|
37
|
+
echo "Error: jq is required. Install with: brew install jq" >&2
|
|
38
|
+
exit 1
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Initialize registry if it doesn't exist
|
|
42
|
+
if [ ! -f "$REGISTRY" ]; then
|
|
43
|
+
mkdir -p "$(dirname "$REGISTRY")"
|
|
44
|
+
cat > "$REGISTRY" << EOF
|
|
45
|
+
{
|
|
46
|
+
"worktrees": [],
|
|
47
|
+
"portPool": {
|
|
48
|
+
"start": $PORT_START,
|
|
49
|
+
"end": $PORT_END,
|
|
50
|
+
"allocated": []
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
EOF
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# Get currently allocated ports from registry
|
|
57
|
+
ALLOCATED_PORTS=$(jq -r '.portPool.allocated // [] | .[]' "$REGISTRY" 2>/dev/null || echo "")
|
|
58
|
+
|
|
59
|
+
# Function to check if port is in use (by system or in registry)
|
|
60
|
+
is_port_available() {
|
|
61
|
+
local port=$1
|
|
62
|
+
|
|
63
|
+
# Check if in registry's allocated list
|
|
64
|
+
if echo "$ALLOCATED_PORTS" | grep -q "^${port}$"; then
|
|
65
|
+
return 1
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# Check if port is actually in use by system
|
|
69
|
+
if lsof -i :"$port" &>/dev/null; then
|
|
70
|
+
return 1
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
return 0
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# Find available ports
|
|
77
|
+
FOUND_PORTS=()
|
|
78
|
+
for ((port=PORT_START; port<=PORT_END; port++)); do
|
|
79
|
+
if is_port_available "$port"; then
|
|
80
|
+
FOUND_PORTS+=("$port")
|
|
81
|
+
if [ ${#FOUND_PORTS[@]} -eq "$COUNT" ]; then
|
|
82
|
+
break
|
|
83
|
+
fi
|
|
84
|
+
fi
|
|
85
|
+
done
|
|
86
|
+
|
|
87
|
+
# Check if we found enough ports
|
|
88
|
+
if [ ${#FOUND_PORTS[@]} -lt "$COUNT" ]; then
|
|
89
|
+
echo "Error: Could not find $COUNT available ports in range $PORT_START-$PORT_END" >&2
|
|
90
|
+
echo "Found only: ${FOUND_PORTS[*]}" >&2
|
|
91
|
+
exit 1
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# Update registry with newly allocated ports
|
|
95
|
+
TMP=$(mktemp)
|
|
96
|
+
PORTS_JSON=$(printf '%s\n' "${FOUND_PORTS[@]}" | jq -R 'tonumber' | jq -s .)
|
|
97
|
+
jq ".portPool.allocated = ((.portPool.allocated // []) + $PORTS_JSON | unique | sort_by(.))" "$REGISTRY" > "$TMP" && mv "$TMP" "$REGISTRY"
|
|
98
|
+
|
|
99
|
+
# Output the ports (space-separated)
|
|
100
|
+
echo "${FOUND_PORTS[*]}"
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# cleanup.sh - Full cleanup of a worktree (ports, directory, registry, optionally branch)
|
|
3
|
+
#
|
|
4
|
+
# Usage: ./cleanup.sh <project> <branch> [--delete-branch]
|
|
5
|
+
# ./cleanup.sh --merged [--delete-branch]
|
|
6
|
+
#
|
|
7
|
+
# Examples:
|
|
8
|
+
# ./cleanup.sh obsidian-ai-agent feature/auth # Cleanup worktree only
|
|
9
|
+
# ./cleanup.sh obsidian-ai-agent feature/auth --delete-branch # Also delete git branch
|
|
10
|
+
# ./cleanup.sh --merged # Cleanup all merged worktrees
|
|
11
|
+
# ./cleanup.sh --merged --delete-branch # Also delete branches
|
|
12
|
+
#
|
|
13
|
+
# This script:
|
|
14
|
+
# 1. Kills processes on allocated ports
|
|
15
|
+
# 2. Removes the worktree directory
|
|
16
|
+
# 3. Prunes git worktree references
|
|
17
|
+
# 4. Removes entry from global registry
|
|
18
|
+
# 5. Releases ports back to pool
|
|
19
|
+
# 6. Optionally deletes local and remote git branches
|
|
20
|
+
|
|
21
|
+
set -e
|
|
22
|
+
|
|
23
|
+
REGISTRY="${HOME}/.claude/worktree-registry.json"
|
|
24
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
25
|
+
|
|
26
|
+
# Handle --merged mode
|
|
27
|
+
if [ "$1" = "--merged" ]; then
|
|
28
|
+
DELETE_BRANCH="${2:-}"
|
|
29
|
+
|
|
30
|
+
echo "Finding worktrees with merged PRs..."
|
|
31
|
+
echo "─────────────────────────────────────────────────────────"
|
|
32
|
+
|
|
33
|
+
CLEANED=0
|
|
34
|
+
SKIPPED=0
|
|
35
|
+
|
|
36
|
+
while IFS= read -r entry; do
|
|
37
|
+
[ -z "$entry" ] && continue
|
|
38
|
+
|
|
39
|
+
PROJECT=$(echo "$entry" | jq -r '.project')
|
|
40
|
+
BRANCH=$(echo "$entry" | jq -r '.branch')
|
|
41
|
+
|
|
42
|
+
# Check PR status
|
|
43
|
+
PR_INFO=$(gh pr list --head "$BRANCH" --state all --json number,state --limit 1 2>/dev/null || echo "[]")
|
|
44
|
+
PR_STATE=$(echo "$PR_INFO" | jq -r '.[0].state // "NONE"')
|
|
45
|
+
PR_NUM=$(echo "$PR_INFO" | jq -r '.[0].number // "?"')
|
|
46
|
+
|
|
47
|
+
if [ "$PR_STATE" = "MERGED" ]; then
|
|
48
|
+
echo ""
|
|
49
|
+
echo "Found merged: $PROJECT / $BRANCH (PR #$PR_NUM)"
|
|
50
|
+
"$SCRIPT_DIR/cleanup.sh" "$PROJECT" "$BRANCH" $DELETE_BRANCH
|
|
51
|
+
CLEANED=$((CLEANED + 1))
|
|
52
|
+
else
|
|
53
|
+
SKIPPED=$((SKIPPED + 1))
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
done < <(jq -c '.worktrees[]' "$REGISTRY" 2>/dev/null)
|
|
57
|
+
|
|
58
|
+
echo ""
|
|
59
|
+
echo "─────────────────────────────────────────────────────────"
|
|
60
|
+
echo "Cleaned: $CLEANED worktrees"
|
|
61
|
+
echo "Skipped: $SKIPPED worktrees (not merged)"
|
|
62
|
+
exit 0
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
PROJECT="$1"
|
|
66
|
+
BRANCH="$2"
|
|
67
|
+
DELETE_BRANCH="${3:-}"
|
|
68
|
+
|
|
69
|
+
if [ -z "$PROJECT" ] || [ -z "$BRANCH" ]; then
|
|
70
|
+
echo "Usage: $0 <project> <branch> [--delete-branch]"
|
|
71
|
+
echo " $0 --merged [--delete-branch]"
|
|
72
|
+
exit 1
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
# Check jq is available
|
|
76
|
+
if ! command -v jq &> /dev/null; then
|
|
77
|
+
echo "Error: jq is required. Install with: brew install jq"
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# Check if registry exists
|
|
82
|
+
if [ ! -f "$REGISTRY" ]; then
|
|
83
|
+
echo "Error: No registry found at: $REGISTRY"
|
|
84
|
+
exit 1
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
echo "Cleaning up: $PROJECT / $BRANCH"
|
|
88
|
+
echo "─────────────────────────────────────────────────────────"
|
|
89
|
+
|
|
90
|
+
# Find worktree entry in registry
|
|
91
|
+
ENTRY=$(jq -c ".worktrees[] | select(.project == \"$PROJECT\" and .branch == \"$BRANCH\")" "$REGISTRY" 2>/dev/null || echo "")
|
|
92
|
+
|
|
93
|
+
if [ -z "$ENTRY" ]; then
|
|
94
|
+
echo "Warning: Worktree not found in registry"
|
|
95
|
+
echo "Attempting cleanup based on project/branch names..."
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
# Get details from entry (or defaults)
|
|
99
|
+
if [ -n "$ENTRY" ]; then
|
|
100
|
+
WORKTREE_PATH=$(echo "$ENTRY" | jq -r '.worktreePath')
|
|
101
|
+
REPO_PATH=$(echo "$ENTRY" | jq -r '.repoPath')
|
|
102
|
+
PORTS=$(echo "$ENTRY" | jq -r '.ports[]' 2>/dev/null || echo "")
|
|
103
|
+
else
|
|
104
|
+
# Construct default path
|
|
105
|
+
BRANCH_SLUG=$(echo "$BRANCH" | tr '/' '-')
|
|
106
|
+
WORKTREE_PATH="$HOME/tmp/worktrees/$PROJECT/$BRANCH_SLUG"
|
|
107
|
+
REPO_PATH=""
|
|
108
|
+
PORTS=""
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
# Step 1: Kill processes on ports
|
|
112
|
+
if [ -n "$PORTS" ]; then
|
|
113
|
+
echo "Killing processes on allocated ports..."
|
|
114
|
+
for PORT in $PORTS; do
|
|
115
|
+
if lsof -ti:"$PORT" &>/dev/null; then
|
|
116
|
+
lsof -ti:"$PORT" | xargs kill -9 2>/dev/null && echo " Killed process on port $PORT" || echo " Failed to kill on port $PORT"
|
|
117
|
+
else
|
|
118
|
+
echo " Port $PORT: no process"
|
|
119
|
+
fi
|
|
120
|
+
done
|
|
121
|
+
else
|
|
122
|
+
echo "No ports registered, skipping port cleanup"
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
# Step 2: Remove worktree directory
|
|
126
|
+
if [ -d "$WORKTREE_PATH" ]; then
|
|
127
|
+
echo "Removing worktree directory: $WORKTREE_PATH"
|
|
128
|
+
|
|
129
|
+
# Try to find the main repo to run git worktree remove
|
|
130
|
+
if [ -n "$REPO_PATH" ] && [ -d "$REPO_PATH" ]; then
|
|
131
|
+
cd "$REPO_PATH"
|
|
132
|
+
git worktree remove "$WORKTREE_PATH" --force 2>/dev/null && echo " Removed via git worktree" || {
|
|
133
|
+
echo " Git worktree remove failed, removing directory directly..."
|
|
134
|
+
rm -rf "$WORKTREE_PATH" && echo " Removed directory"
|
|
135
|
+
}
|
|
136
|
+
else
|
|
137
|
+
# Just remove the directory
|
|
138
|
+
rm -rf "$WORKTREE_PATH" && echo " Removed directory"
|
|
139
|
+
fi
|
|
140
|
+
else
|
|
141
|
+
echo "Worktree directory not found: $WORKTREE_PATH"
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
# Step 3: Prune stale worktree references
|
|
145
|
+
if [ -n "$REPO_PATH" ] && [ -d "$REPO_PATH" ]; then
|
|
146
|
+
echo "Pruning stale git worktree references..."
|
|
147
|
+
cd "$REPO_PATH"
|
|
148
|
+
git worktree prune 2>/dev/null && echo " Pruned" || echo " Prune skipped"
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
# Step 4: Remove from registry and release ports
|
|
152
|
+
echo "Updating global registry..."
|
|
153
|
+
TMP=$(mktemp)
|
|
154
|
+
|
|
155
|
+
# Remove worktree entry
|
|
156
|
+
jq "del(.worktrees[] | select(.project == \"$PROJECT\" and .branch == \"$BRANCH\"))" "$REGISTRY" > "$TMP"
|
|
157
|
+
|
|
158
|
+
# Release ports from allocated pool
|
|
159
|
+
if [ -n "$PORTS" ]; then
|
|
160
|
+
for PORT in $PORTS; do
|
|
161
|
+
jq ".portPool.allocated = (.portPool.allocated | map(select(. != $PORT)))" "$TMP" > "${TMP}.2" && mv "${TMP}.2" "$TMP"
|
|
162
|
+
done
|
|
163
|
+
echo " Released ports: $PORTS"
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
mv "$TMP" "$REGISTRY"
|
|
167
|
+
echo " Registry updated"
|
|
168
|
+
|
|
169
|
+
# Step 5: Delete git branches (if requested)
|
|
170
|
+
if [ "$DELETE_BRANCH" = "--delete-branch" ]; then
|
|
171
|
+
if [ -n "$REPO_PATH" ] && [ -d "$REPO_PATH" ]; then
|
|
172
|
+
cd "$REPO_PATH"
|
|
173
|
+
|
|
174
|
+
echo "Deleting local branch: $BRANCH"
|
|
175
|
+
git branch -D "$BRANCH" 2>/dev/null && echo " Deleted local branch" || echo " Local branch not found or is current branch"
|
|
176
|
+
|
|
177
|
+
echo "Deleting remote branch: $BRANCH"
|
|
178
|
+
git push origin --delete "$BRANCH" 2>/dev/null && echo " Deleted remote branch" || echo " Remote branch not found or already deleted"
|
|
179
|
+
else
|
|
180
|
+
echo "Cannot delete branches: original repo path not found"
|
|
181
|
+
fi
|
|
182
|
+
fi
|
|
183
|
+
|
|
184
|
+
echo "─────────────────────────────────────────────────────────"
|
|
185
|
+
echo "✅ Cleanup complete: $PROJECT / $BRANCH"
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# launch-agent.sh - Launch Claude Code in a new Ghostty terminal for a worktree
|
|
3
|
+
#
|
|
4
|
+
# Usage: ./launch-agent.sh <worktree-path> [task-description]
|
|
5
|
+
#
|
|
6
|
+
# Examples:
|
|
7
|
+
# ./launch-agent.sh ~/tmp/worktrees/my-project/feature-auth
|
|
8
|
+
# ./launch-agent.sh ~/tmp/worktrees/my-project/feature-auth "Implement OAuth login"
|
|
9
|
+
|
|
10
|
+
set -e
|
|
11
|
+
|
|
12
|
+
WORKTREE_PATH="$1"
|
|
13
|
+
TASK="$2"
|
|
14
|
+
|
|
15
|
+
# Validate input
|
|
16
|
+
if [ -z "$WORKTREE_PATH" ]; then
|
|
17
|
+
echo "Error: Worktree path required"
|
|
18
|
+
echo "Usage: $0 <worktree-path> [task-description]"
|
|
19
|
+
exit 1
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
# Find script directory and config
|
|
23
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
24
|
+
CONFIG_FILE="$SCRIPT_DIR/../config.json"
|
|
25
|
+
|
|
26
|
+
# Load config (with defaults)
|
|
27
|
+
if [ -f "$CONFIG_FILE" ] && command -v jq &> /dev/null; then
|
|
28
|
+
TERMINAL=$(jq -r '.terminal // "ghostty"' "$CONFIG_FILE")
|
|
29
|
+
SHELL_CMD=$(jq -r '.shell // "fish"' "$CONFIG_FILE")
|
|
30
|
+
CLAUDE_CMD=$(jq -r '.claudeCommand // "cc"' "$CONFIG_FILE")
|
|
31
|
+
else
|
|
32
|
+
TERMINAL="ghostty"
|
|
33
|
+
SHELL_CMD="fish"
|
|
34
|
+
CLAUDE_CMD="cc"
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# Note: CLAUDE_CMD (default "cc") is configurable in config.json
|
|
38
|
+
# It runs inside the target shell (fish) which should have the alias defined
|
|
39
|
+
# Falls back to "claude" if the alias/command fails
|
|
40
|
+
|
|
41
|
+
# Expand ~ in path
|
|
42
|
+
WORKTREE_PATH="${WORKTREE_PATH/#\~/$HOME}"
|
|
43
|
+
|
|
44
|
+
# Convert to absolute path if relative
|
|
45
|
+
if [[ "$WORKTREE_PATH" != /* ]]; then
|
|
46
|
+
WORKTREE_PATH="$(pwd)/$WORKTREE_PATH"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# Verify worktree exists
|
|
50
|
+
if [ ! -d "$WORKTREE_PATH" ]; then
|
|
51
|
+
echo "Error: Worktree directory does not exist: $WORKTREE_PATH"
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# Verify it's a git worktree (has .git file or directory)
|
|
56
|
+
if [ ! -e "$WORKTREE_PATH/.git" ]; then
|
|
57
|
+
echo "Error: Not a git worktree: $WORKTREE_PATH"
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# Get branch name
|
|
62
|
+
BRANCH=$(cd "$WORKTREE_PATH" && git branch --show-current 2>/dev/null || basename "$WORKTREE_PATH")
|
|
63
|
+
|
|
64
|
+
# Get project name from path
|
|
65
|
+
PROJECT=$(basename "$(dirname "$WORKTREE_PATH")")
|
|
66
|
+
|
|
67
|
+
# Build the command to run in the new terminal
|
|
68
|
+
# Use configured command (cc) - fish syntax compatible
|
|
69
|
+
# For fish: use 'or' instead of '||' for fallback, and avoid subshells
|
|
70
|
+
if [ "$SHELL_CMD" = "fish" ]; then
|
|
71
|
+
if [ -n "$TASK" ]; then
|
|
72
|
+
INNER_CMD="cd '$WORKTREE_PATH'; and echo '🌳 Worktree: $PROJECT / $BRANCH'; and echo '📋 Task: $TASK'; and echo ''; and $CLAUDE_CMD; or claude"
|
|
73
|
+
else
|
|
74
|
+
INNER_CMD="cd '$WORKTREE_PATH'; and echo '🌳 Worktree: $PROJECT / $BRANCH'; and echo ''; and $CLAUDE_CMD; or claude"
|
|
75
|
+
fi
|
|
76
|
+
else
|
|
77
|
+
# bash/zsh syntax
|
|
78
|
+
if [ -n "$TASK" ]; then
|
|
79
|
+
INNER_CMD="cd '$WORKTREE_PATH' && echo '🌳 Worktree: $PROJECT / $BRANCH' && echo '📋 Task: $TASK' && echo '' && ($CLAUDE_CMD || claude)"
|
|
80
|
+
else
|
|
81
|
+
INNER_CMD="cd '$WORKTREE_PATH' && echo '🌳 Worktree: $PROJECT / $BRANCH' && echo '' && ($CLAUDE_CMD || claude)"
|
|
82
|
+
fi
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# Launch based on terminal type
|
|
86
|
+
case "$TERMINAL" in
|
|
87
|
+
ghostty)
|
|
88
|
+
if ! command -v ghostty &> /dev/null && [ ! -d "/Applications/Ghostty.app" ]; then
|
|
89
|
+
echo "Error: Ghostty not found"
|
|
90
|
+
exit 1
|
|
91
|
+
fi
|
|
92
|
+
# Launch Ghostty with the command
|
|
93
|
+
open -na "Ghostty.app" --args -e "$SHELL_CMD" -c "$INNER_CMD"
|
|
94
|
+
;;
|
|
95
|
+
|
|
96
|
+
iterm2|iterm)
|
|
97
|
+
osascript <<EOF
|
|
98
|
+
tell application "iTerm2"
|
|
99
|
+
create window with default profile
|
|
100
|
+
tell current session of current window
|
|
101
|
+
write text "cd '$WORKTREE_PATH' && $CLAUDE_CMD"
|
|
102
|
+
end tell
|
|
103
|
+
end tell
|
|
104
|
+
EOF
|
|
105
|
+
;;
|
|
106
|
+
|
|
107
|
+
tmux)
|
|
108
|
+
if ! command -v tmux &> /dev/null; then
|
|
109
|
+
echo "Error: tmux not found"
|
|
110
|
+
exit 1
|
|
111
|
+
fi
|
|
112
|
+
SESSION_NAME="wt-$PROJECT-$(echo "$BRANCH" | tr '/' '-')"
|
|
113
|
+
tmux new-session -d -s "$SESSION_NAME" -c "$WORKTREE_PATH" "$SHELL_CMD -c '$CLAUDE_CMD'"
|
|
114
|
+
echo " tmux session: $SESSION_NAME (attach with: tmux attach -t $SESSION_NAME)"
|
|
115
|
+
;;
|
|
116
|
+
|
|
117
|
+
wezterm)
|
|
118
|
+
if ! command -v wezterm &> /dev/null; then
|
|
119
|
+
echo "Error: WezTerm not found"
|
|
120
|
+
exit 1
|
|
121
|
+
fi
|
|
122
|
+
wezterm start --cwd "$WORKTREE_PATH" -- "$SHELL_CMD" -c "$INNER_CMD"
|
|
123
|
+
;;
|
|
124
|
+
|
|
125
|
+
kitty)
|
|
126
|
+
if ! command -v kitty &> /dev/null; then
|
|
127
|
+
echo "Error: Kitty not found"
|
|
128
|
+
exit 1
|
|
129
|
+
fi
|
|
130
|
+
kitty --detach --directory "$WORKTREE_PATH" "$SHELL_CMD" -c "$INNER_CMD"
|
|
131
|
+
;;
|
|
132
|
+
|
|
133
|
+
alacritty)
|
|
134
|
+
if ! command -v alacritty &> /dev/null; then
|
|
135
|
+
echo "Error: Alacritty not found"
|
|
136
|
+
exit 1
|
|
137
|
+
fi
|
|
138
|
+
alacritty --working-directory "$WORKTREE_PATH" -e "$SHELL_CMD" -c "$INNER_CMD" &
|
|
139
|
+
;;
|
|
140
|
+
|
|
141
|
+
*)
|
|
142
|
+
echo "Error: Unknown terminal type: $TERMINAL"
|
|
143
|
+
echo "Supported: ghostty, iterm2, tmux, wezterm, kitty, alacritty"
|
|
144
|
+
exit 1
|
|
145
|
+
;;
|
|
146
|
+
esac
|
|
147
|
+
|
|
148
|
+
echo "✅ Launched Claude Code agent"
|
|
149
|
+
echo " Terminal: $TERMINAL"
|
|
150
|
+
echo " Project: $PROJECT"
|
|
151
|
+
echo " Branch: $BRANCH"
|
|
152
|
+
echo " Path: $WORKTREE_PATH"
|
|
153
|
+
if [ -n "$TASK" ]; then
|
|
154
|
+
echo " Task: $TASK"
|
|
155
|
+
fi
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# register.sh - Register a worktree in the global registry
|
|
3
|
+
#
|
|
4
|
+
# Usage: ./register.sh <project> <branch> <branch-slug> <worktree-path> <repo-path> <ports> [task]
|
|
5
|
+
#
|
|
6
|
+
# Arguments:
|
|
7
|
+
# project - Project name (e.g., "obsidian-ai-agent")
|
|
8
|
+
# branch - Full branch name (e.g., "feature/auth")
|
|
9
|
+
# branch-slug - Slugified branch (e.g., "feature-auth")
|
|
10
|
+
# worktree-path - Full path to worktree
|
|
11
|
+
# repo-path - Full path to original repo
|
|
12
|
+
# ports - Comma-separated ports (e.g., "8100,8101")
|
|
13
|
+
# task - Optional task description
|
|
14
|
+
#
|
|
15
|
+
# Example:
|
|
16
|
+
# ./register.sh obsidian-ai-agent feature/auth feature-auth \
|
|
17
|
+
# ~/tmp/worktrees/obsidian-ai-agent/feature-auth \
|
|
18
|
+
# ~/Projects/obsidian-ai-agent \
|
|
19
|
+
# 8100,8101 "Implement OAuth"
|
|
20
|
+
|
|
21
|
+
set -e
|
|
22
|
+
|
|
23
|
+
PROJECT="$1"
|
|
24
|
+
BRANCH="$2"
|
|
25
|
+
BRANCH_SLUG="$3"
|
|
26
|
+
WORKTREE_PATH="$4"
|
|
27
|
+
REPO_PATH="$5"
|
|
28
|
+
PORTS="$6"
|
|
29
|
+
TASK="${7:-}"
|
|
30
|
+
|
|
31
|
+
# Validate inputs
|
|
32
|
+
if [ -z "$PROJECT" ] || [ -z "$BRANCH" ] || [ -z "$BRANCH_SLUG" ] || [ -z "$WORKTREE_PATH" ] || [ -z "$REPO_PATH" ] || [ -z "$PORTS" ]; then
|
|
33
|
+
echo "Usage: $0 <project> <branch> <branch-slug> <worktree-path> <repo-path> <ports> [task]"
|
|
34
|
+
exit 1
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
REGISTRY="${HOME}/.claude/worktree-registry.json"
|
|
38
|
+
|
|
39
|
+
# Check jq is available
|
|
40
|
+
if ! command -v jq &> /dev/null; then
|
|
41
|
+
echo "Error: jq is required. Install with: brew install jq"
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# Expand ~ in paths
|
|
46
|
+
WORKTREE_PATH="${WORKTREE_PATH/#\~/$HOME}"
|
|
47
|
+
REPO_PATH="${REPO_PATH/#\~/$HOME}"
|
|
48
|
+
|
|
49
|
+
# Initialize registry if it doesn't exist
|
|
50
|
+
if [ ! -f "$REGISTRY" ]; then
|
|
51
|
+
mkdir -p "$(dirname "$REGISTRY")"
|
|
52
|
+
cat > "$REGISTRY" << 'EOF'
|
|
53
|
+
{
|
|
54
|
+
"worktrees": [],
|
|
55
|
+
"portPool": {
|
|
56
|
+
"start": 8100,
|
|
57
|
+
"end": 8199,
|
|
58
|
+
"allocated": []
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
EOF
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# Check if already registered - release old ports before updating
|
|
65
|
+
if jq -e ".worktrees[] | select(.project == \"$PROJECT\" and .branch == \"$BRANCH\")" "$REGISTRY" > /dev/null 2>&1; then
|
|
66
|
+
echo "Warning: Worktree already registered, updating..."
|
|
67
|
+
|
|
68
|
+
# Get old ports to release them
|
|
69
|
+
OLD_PORTS=$(jq -r ".worktrees[] | select(.project == \"$PROJECT\" and .branch == \"$BRANCH\") | .ports[]" "$REGISTRY" 2>/dev/null || echo "")
|
|
70
|
+
|
|
71
|
+
TMP=$(mktemp)
|
|
72
|
+
# Remove old entry
|
|
73
|
+
jq "del(.worktrees[] | select(.project == \"$PROJECT\" and .branch == \"$BRANCH\"))" "$REGISTRY" > "$TMP"
|
|
74
|
+
|
|
75
|
+
# Release old ports from pool
|
|
76
|
+
if [ -n "$OLD_PORTS" ]; then
|
|
77
|
+
for OLD_PORT in $OLD_PORTS; do
|
|
78
|
+
jq ".portPool.allocated = (.portPool.allocated | map(select(. != $OLD_PORT)))" "$TMP" > "${TMP}.2" && mv "${TMP}.2" "$TMP"
|
|
79
|
+
done
|
|
80
|
+
echo " Released old ports: $OLD_PORTS"
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
mv "$TMP" "$REGISTRY"
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# Parse ports into JSON array
|
|
87
|
+
PORTS_JSON=$(echo "$PORTS" | tr ',' '\n' | jq -R 'tonumber' | jq -s .)
|
|
88
|
+
|
|
89
|
+
# Format task
|
|
90
|
+
if [ -n "$TASK" ]; then
|
|
91
|
+
TASK_JSON="\"$TASK\""
|
|
92
|
+
else
|
|
93
|
+
TASK_JSON="null"
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# Generate UUID
|
|
97
|
+
UUID=$(uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "wt-$(date +%s)-$$")
|
|
98
|
+
|
|
99
|
+
# Add entry
|
|
100
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
101
|
+
TMP=$(mktemp)
|
|
102
|
+
jq ".worktrees += [{
|
|
103
|
+
\"id\": \"$UUID\",
|
|
104
|
+
\"project\": \"$PROJECT\",
|
|
105
|
+
\"repoPath\": \"$REPO_PATH\",
|
|
106
|
+
\"branch\": \"$BRANCH\",
|
|
107
|
+
\"branchSlug\": \"$BRANCH_SLUG\",
|
|
108
|
+
\"worktreePath\": \"$WORKTREE_PATH\",
|
|
109
|
+
\"ports\": $PORTS_JSON,
|
|
110
|
+
\"createdAt\": \"$TIMESTAMP\",
|
|
111
|
+
\"validatedAt\": null,
|
|
112
|
+
\"agentLaunchedAt\": null,
|
|
113
|
+
\"task\": $TASK_JSON,
|
|
114
|
+
\"prNumber\": null,
|
|
115
|
+
\"status\": \"active\"
|
|
116
|
+
}]" "$REGISTRY" > "$TMP" && mv "$TMP" "$REGISTRY"
|
|
117
|
+
|
|
118
|
+
echo "✅ Registered worktree:"
|
|
119
|
+
echo " Project: $PROJECT"
|
|
120
|
+
echo " Branch: $BRANCH"
|
|
121
|
+
echo " Path: $WORKTREE_PATH"
|
|
122
|
+
echo " Ports: $PORTS"
|
|
123
|
+
if [ -n "$TASK" ]; then
|
|
124
|
+
echo " Task: $TASK"
|
|
125
|
+
fi
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# release-ports.sh - Release ports back to the global pool
|
|
3
|
+
#
|
|
4
|
+
# Usage: ./release-ports.sh <port1> [port2] [port3] ...
|
|
5
|
+
#
|
|
6
|
+
# Example: ./release-ports.sh 8100 8101
|
|
7
|
+
|
|
8
|
+
set -e
|
|
9
|
+
|
|
10
|
+
if [ $# -eq 0 ]; then
|
|
11
|
+
echo "Usage: $0 <port1> [port2] [port3] ..."
|
|
12
|
+
exit 1
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
REGISTRY="${HOME}/.claude/worktree-registry.json"
|
|
16
|
+
|
|
17
|
+
# Check jq is available
|
|
18
|
+
if ! command -v jq &> /dev/null; then
|
|
19
|
+
echo "Error: jq is required. Install with: brew install jq"
|
|
20
|
+
exit 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
# Check if registry exists
|
|
24
|
+
if [ ! -f "$REGISTRY" ]; then
|
|
25
|
+
echo "No registry found, nothing to release"
|
|
26
|
+
exit 0
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
TMP=$(mktemp)
|
|
30
|
+
cp "$REGISTRY" "$TMP"
|
|
31
|
+
|
|
32
|
+
RELEASED=()
|
|
33
|
+
for PORT in "$@"; do
|
|
34
|
+
if [[ "$PORT" =~ ^[0-9]+$ ]]; then
|
|
35
|
+
jq ".portPool.allocated = (.portPool.allocated | map(select(. != $PORT)))" "$TMP" > "${TMP}.2" && mv "${TMP}.2" "$TMP"
|
|
36
|
+
RELEASED+=("$PORT")
|
|
37
|
+
else
|
|
38
|
+
echo "Warning: Invalid port number: $PORT" >&2
|
|
39
|
+
fi
|
|
40
|
+
done
|
|
41
|
+
|
|
42
|
+
mv "$TMP" "$REGISTRY"
|
|
43
|
+
|
|
44
|
+
if [ ${#RELEASED[@]} -gt 0 ]; then
|
|
45
|
+
echo "Released ports: ${RELEASED[*]}"
|
|
46
|
+
else
|
|
47
|
+
echo "No ports released"
|
|
48
|
+
fi
|