Initial commit
This commit is contained in:
14
.claude-plugin/plugin.json
Normal file
14
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "jjagent",
|
||||||
|
"description": "Track Claude Code sessions as jujutsu changes",
|
||||||
|
"version": "0.4.2",
|
||||||
|
"author": {
|
||||||
|
"name": "schpet"
|
||||||
|
},
|
||||||
|
"commands": [
|
||||||
|
"./commands"
|
||||||
|
],
|
||||||
|
"hooks": [
|
||||||
|
"./hooks"
|
||||||
|
]
|
||||||
|
}
|
||||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# jjagent
|
||||||
|
|
||||||
|
Track Claude Code sessions as jujutsu changes
|
||||||
82
commands/describe.md
Normal file
82
commands/describe.md
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
---
|
||||||
|
description: Generate a commit description for the current session's jj change
|
||||||
|
model: claude-haiku-4-5
|
||||||
|
allowed-tools: Bash(jjagent:*), Bash(jj:*)
|
||||||
|
---
|
||||||
|
|
||||||
|
# jj-describe
|
||||||
|
|
||||||
|
Generate a commit description for a Claude session's jj change
|
||||||
|
|
||||||
|
## instructions
|
||||||
|
|
||||||
|
You must follow these steps to create a proper commit message:
|
||||||
|
|
||||||
|
1. **Determine session ID:**
|
||||||
|
- Use the session ID from the system reminder (current session)
|
||||||
|
- Store the session ID for use in subsequent steps
|
||||||
|
|
||||||
|
2. **Check if a change exists for the session:**
|
||||||
|
- Run: `jjagent change-id <session-id>` to check if a change exists
|
||||||
|
- **IMPORTANT:** If the command fails or returns an error, immediately stop and inform the user:
|
||||||
|
"No jj change exists for this session yet. There's nothing to describe."
|
||||||
|
- Do NOT proceed to the next steps if no change ID is found
|
||||||
|
|
||||||
|
3. **Gather context:**
|
||||||
|
- Run: `jj diff -r "$(jjagent change-id <session-id>)"` to see ONLY the diff
|
||||||
|
- Review the diff to understand what was actually changed
|
||||||
|
- Review the conversation/context to understand why a change was made
|
||||||
|
- **Do NOT read the existing commit message** - it will be replaced entirely
|
||||||
|
|
||||||
|
4. **Generate a NEW commit message:**
|
||||||
|
- **First line (subject):**
|
||||||
|
- 50 characters or less
|
||||||
|
- Capitalize the first letter
|
||||||
|
- Use imperative mood (e.g., "Add feature" not "Added feature" or "Adds feature")
|
||||||
|
- No period at the end
|
||||||
|
- Concise summary of the change, not just "jjagent: session <id>"
|
||||||
|
- **Second line:** Blank
|
||||||
|
- **Body (if needed):**
|
||||||
|
- Wrap at 72 characters
|
||||||
|
- Provide more detailed explanatory text with technical details, but stay concise
|
||||||
|
- Explain what and why, not how the code works
|
||||||
|
- Use bullet points for multiple items if appropriate
|
||||||
|
- Blank lines separate paragraphs
|
||||||
|
|
||||||
|
5. **Update the description:**
|
||||||
|
- Run: `jjagent describe <session-id> -m "your commit message here"`
|
||||||
|
- **Do NOT include any trailers** (Claude-session-id, etc.) - they are preserved automatically
|
||||||
|
- Only include the subject line and body
|
||||||
|
- Use a heredoc or proper quoting to preserve formatting
|
||||||
|
- Note: This is the Rust CLI tool command, not the slash command
|
||||||
|
|
||||||
|
6. **Show the final change**
|
||||||
|
- Run: `jj show "$(jjagent change-id <session-id>) -s` and show the user direct output formatted as a code block
|
||||||
|
|
||||||
|
## Example commit message (what you pass to `jjagent describe`):
|
||||||
|
|
||||||
|
```
|
||||||
|
Add SessionStart and UserPromptSubmit hooks
|
||||||
|
|
||||||
|
Implement hook handlers that inject the session ID into Claude's
|
||||||
|
context at the start of a session and re-inject it when it's been
|
||||||
|
lost from the recent transcript.
|
||||||
|
|
||||||
|
- Add HookSpecificOutput structure for passing context to Claude
|
||||||
|
- Implement handle_session_start_hook to inject session ID
|
||||||
|
- Implement handle_user_prompt_submit_hook to re-inject when needed
|
||||||
|
- Add comprehensive tests for both hook handlers
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: Do NOT include the `Claude-session-id` trailer - it's preserved automatically.
|
||||||
|
|
||||||
|
## Important notes:
|
||||||
|
|
||||||
|
- Do NOT use the generic "jjagent: session <id>" format for the subject line
|
||||||
|
- DO write a concise summary in the subject, with technical details in the body
|
||||||
|
- DO analyze the actual changes and write a meaningful, specific subject
|
||||||
|
- DO use imperative mood ("Add", "Fix", "Refactor", not "Added", "Fixed", "Refactored")
|
||||||
|
- DO keep the subject line to 50 characters or less
|
||||||
|
- DO wrap body lines at 72 characters
|
||||||
|
- Do NOT include trailers - they are preserved automatically by `jjagent describe`
|
||||||
|
- Do NOT look at the existing commit message - generate a fresh one from the diff
|
||||||
78
commands/insert-after.md
Normal file
78
commands/insert-after.md
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
---
|
||||||
|
description: Insert a new session change after a specific revision
|
||||||
|
argument-hint: <ref> [message]
|
||||||
|
model: claude-haiku-4-5
|
||||||
|
allowed-tools: Bash(jjagent:*), Bash(jj:*)
|
||||||
|
---
|
||||||
|
|
||||||
|
# jjagent:insert-after
|
||||||
|
|
||||||
|
Insert a new session change after a specific revision using jj's --insert-after flag
|
||||||
|
|
||||||
|
## instructions
|
||||||
|
|
||||||
|
You must follow these steps:
|
||||||
|
|
||||||
|
1. **Parse arguments:**
|
||||||
|
- `$1` (required): The jj reference to insert after
|
||||||
|
- `$2 $3 $4...` (optional): Custom commit message for the session (all remaining arguments)
|
||||||
|
- If `$1` is empty, inform the user that a reference is required
|
||||||
|
|
||||||
|
2. **Get the current session ID:**
|
||||||
|
- Extract it from the system reminder at the start of this conversation
|
||||||
|
- The format is: "The current session ID is <uuid>"
|
||||||
|
|
||||||
|
3. **Check if a session change already exists:**
|
||||||
|
- Run: `jjagent change-id <session-id>`
|
||||||
|
- If this succeeds and returns a change ID, the session already has a change
|
||||||
|
- If it fails, the session doesn't have a change yet
|
||||||
|
|
||||||
|
4. **Validate that ref is an ancestor of @ (working copy):**
|
||||||
|
- Run: `jj log -r "$1..@" --no-graph -T "change_id.short()"`
|
||||||
|
- If this command fails or returns empty output, `$1` is not an ancestor of `@`
|
||||||
|
- If not an ancestor, inform the user: "Error: '$1' is not an ancestor of the working copy. Please choose a revision that comes before @ in the commit history."
|
||||||
|
- Stop execution if validation fails
|
||||||
|
|
||||||
|
5. **Handle existing session change:**
|
||||||
|
- If a change already exists for this session, **STOP and ask the user for confirmation**:
|
||||||
|
"This session already has a change at <change-id>. Would you like to rebase it to insert after '$1'?"
|
||||||
|
- **IMPORTANT: You MUST wait for explicit user confirmation before proceeding**
|
||||||
|
- Do NOT rebase without the user's explicit approval
|
||||||
|
- If the user confirms YES, then run: `jj rebase -r <change-id> --insert-after "$1"`
|
||||||
|
- If the user says NO or declines, stop and explain that no changes were made
|
||||||
|
- After rebasing (if confirmed), show the result with: `jj log -r <change-id> --no-graph`
|
||||||
|
|
||||||
|
6. **Create new session change (if no existing change):**
|
||||||
|
- Build the commit message using the session-message command:
|
||||||
|
- If custom message arguments were provided (if `$2` is not empty):
|
||||||
|
- Combine all arguments from `$2` onwards into the message
|
||||||
|
- Run: `jjagent session-message <session-id> "$2 $3 $4..."` (all remaining args)
|
||||||
|
- If no custom message (if `$2` is empty):
|
||||||
|
- Run: `jjagent session-message <session-id>`
|
||||||
|
- Create the change: `jj new --insert-after "$1" --no-edit -m "$(jjagent session-message <session-id> [message if provided])"`
|
||||||
|
- Show the result with: `jj log -r @ --no-graph`
|
||||||
|
|
||||||
|
7. **Inform the user:**
|
||||||
|
- Confirm that the session change has been created/rebased
|
||||||
|
- Explain that future edits will be tracked in this change
|
||||||
|
|
||||||
|
## Example usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Insert session after the parent of working copy
|
||||||
|
/jjagent:insert-after @-
|
||||||
|
|
||||||
|
# Insert with custom message
|
||||||
|
/jjagent:insert-after @-- "Implement user authentication"
|
||||||
|
|
||||||
|
# Insert after a specific change ID
|
||||||
|
/jjagent:insert-after qwerty123
|
||||||
|
```
|
||||||
|
|
||||||
|
## Important notes
|
||||||
|
|
||||||
|
- The `$1` (ref) must be an ancestor of `@` (working copy)
|
||||||
|
- If a session change already exists, offer to rebase it
|
||||||
|
- Always validate the reference before creating/rebasing changes
|
||||||
|
- Use proper quoting when passing `$1` to shell commands
|
||||||
|
- When passing custom messages to `jjagent session-message`, combine all arguments from `$2` onwards
|
||||||
40
commands/into.md
Normal file
40
commands/into.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
description: Choose the change where this session will be squashed into
|
||||||
|
model: claude-haiku-4-5
|
||||||
|
allowed-tools: Bash(jjagent into:*)
|
||||||
|
argument-hint: <ref>
|
||||||
|
---
|
||||||
|
|
||||||
|
# jja-into
|
||||||
|
|
||||||
|
Choose the change where this session will be squashed into
|
||||||
|
|
||||||
|
## instructions
|
||||||
|
|
||||||
|
You must follow these steps:
|
||||||
|
|
||||||
|
1. **Get the current session ID:**
|
||||||
|
- Extract it from the system reminder at the start of this conversation
|
||||||
|
- The format is: "The current session ID is <uuid>"
|
||||||
|
|
||||||
|
2. **Get the target revision:**
|
||||||
|
- The target revision is: $1
|
||||||
|
- This should be a jj reference (change ID, revset, etc.)
|
||||||
|
|
||||||
|
3. **Run the into command:**
|
||||||
|
- Execute: `jjagent into <session-id> $1`
|
||||||
|
- This will move session tracking to the specified revision
|
||||||
|
|
||||||
|
4. **Inform the user:**
|
||||||
|
- Tell them that session tracking has been moved to the specified revision
|
||||||
|
- Explain that future changes will now be tracked with this revision
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
If the session ID is `abcd1234-5678-90ab-cdef-1234567890ab` and the target ref is `@--`, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
jjagent into abcd1234-5678-90ab-cdef-1234567890ab @--
|
||||||
|
```
|
||||||
|
|
||||||
|
Then inform the user that session tracking has been moved to the specified revision.
|
||||||
35
commands/split.md
Normal file
35
commands/split.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
description: Split the current session into a new jj change
|
||||||
|
model: claude-haiku-4-5
|
||||||
|
allowed-tools: Bash(jjagent split:*)
|
||||||
|
---
|
||||||
|
|
||||||
|
# jja-split
|
||||||
|
|
||||||
|
Split the current Claude session into a new jj change
|
||||||
|
|
||||||
|
## instructions
|
||||||
|
|
||||||
|
You must follow these steps:
|
||||||
|
|
||||||
|
1. **Get the current session ID:**
|
||||||
|
- Extract it from the system reminder at the start of this conversation
|
||||||
|
- The format is: "The current session ID is <uuid>"
|
||||||
|
|
||||||
|
2. **Run the split command:**
|
||||||
|
- Execute: `jjagent split <session-id>`
|
||||||
|
- This will create a new change part for the session
|
||||||
|
|
||||||
|
3. **Inform the user:**
|
||||||
|
- Tell them a new change part was created
|
||||||
|
- Explain that future changes will now go into this new part
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
If the session ID is `abcd1234-5678-90ab-cdef-1234567890ab`, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
jjagent split abcd1234-5678-90ab-cdef-1234567890ab
|
||||||
|
```
|
||||||
|
|
||||||
|
Then inform the user that a new change part has been created for the session.
|
||||||
47
hooks/hooks.json
Normal file
47
hooks/hooks.json
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"description": "jjagent hooks for tracking Claude Code sessions as jj changes",
|
||||||
|
"hooks": {
|
||||||
|
"UserPromptSubmit": [
|
||||||
|
{
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "jjagent claude hooks UserPromptSubmit"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"PreToolUse": [
|
||||||
|
{
|
||||||
|
"matcher": "Edit|MultiEdit|Write",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "jjagent claude hooks PreToolUse"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"PostToolUse": [
|
||||||
|
{
|
||||||
|
"matcher": "Edit|MultiEdit|Write",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "jjagent claude hooks PostToolUse"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Stop": [
|
||||||
|
{
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "jjagent claude hooks Stop"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
61
plugin.lock.json
Normal file
61
plugin.lock.json
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||||
|
"pluginId": "gh:schpet/jjagent:",
|
||||||
|
"normalized": {
|
||||||
|
"repo": null,
|
||||||
|
"ref": "refs/tags/v20251128.0",
|
||||||
|
"commit": "eab9eab513e7a486bbb5e6678625740be0f47f4e",
|
||||||
|
"treeHash": "e94079199f40709b79ca7a44465ddc3b44cf5d5d32ad0dbc396ad2991179db48",
|
||||||
|
"generatedAt": "2025-11-28T10:28:09.697913Z",
|
||||||
|
"toolVersion": "publish_plugins.py@0.2.0"
|
||||||
|
},
|
||||||
|
"origin": {
|
||||||
|
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||||
|
"branch": "master",
|
||||||
|
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||||
|
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||||
|
},
|
||||||
|
"manifest": {
|
||||||
|
"name": "jjagent",
|
||||||
|
"description": "Track Claude Code sessions as jujutsu changes",
|
||||||
|
"version": "0.4.2"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"path": "README.md",
|
||||||
|
"sha256": "bab1a5ace93d2421a0c6a474239dcf935f3791b41fec57c151eac519b9a4429d"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/hooks.json",
|
||||||
|
"sha256": "24a01da41be821ef7b8b83c748017357081f3b9908210a5c47b29eac75b02611"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": ".claude-plugin/plugin.json",
|
||||||
|
"sha256": "8690748d936bb1624ff4f4e682f92e4e2c95d617c19fddbd6c0d0975f38fe856"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/split.md",
|
||||||
|
"sha256": "708ec92f4bbc5b685adc081f78741a0b7c8eaad974667d83661f38cbd0c3adc2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/into.md",
|
||||||
|
"sha256": "02e415922c4578c8f6df46725df1fd1758a1b27dca188814e0d6cd2e16a18843"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/describe.md",
|
||||||
|
"sha256": "709ae1a049723960d37b7724bfe3d2dfdd91a0a328baed2b67f8db78a13d988f"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/insert-after.md",
|
||||||
|
"sha256": "11c2e193a3a6abe5c3dd4aaa3fde06d198a237b6c193eb668058c069e0b15897"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dirSha256": "e94079199f40709b79ca7a44465ddc3b44cf5d5d32ad0dbc396ad2991179db48"
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"scannedAt": null,
|
||||||
|
"scannerVersion": null,
|
||||||
|
"flags": []
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user