opencode-gitbutler 0.1.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/LICENSE +21 -0
- package/README.md +147 -0
- package/command/b-branch-commit.md +105 -0
- package/command/b-branch-gc.md +58 -0
- package/command/b-branch-pr.md +221 -0
- package/command/b-branch.md +88 -0
- package/dist/auto-update.d.ts +39 -0
- package/dist/auto-update.d.ts.map +1 -0
- package/dist/cli.d.ts +85 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/config.d.ts +36 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1731 -0
- package/dist/logger.d.ts +21 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/notify.d.ts +11 -0
- package/dist/notify.d.ts.map +1 -0
- package/dist/plugin.d.ts +21 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/reword.d.ts +104 -0
- package/dist/reword.d.ts.map +1 -0
- package/dist/state.d.ts +38 -0
- package/dist/state.d.ts.map +1 -0
- package/package.json +56 -0
- package/postinstall.mjs +10 -0
- package/skill/gitbutler/SKILL.md +275 -0
- package/skill/gitbutler/references/cheatsheet.md +271 -0
- package/skill/gitbutler/references/concepts.md +333 -0
- package/skill/gitbutler/references/examples.md +512 -0
- package/skill/gitbutler/references/reference.md +504 -0
- package/skill/gitbutler/references/tutorial.md +486 -0
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type LogLevel = "info" | "warn" | "error";
|
|
2
|
+
export type Logger = {
|
|
3
|
+
info: (cat: string, data?: Record<string, unknown>) => void;
|
|
4
|
+
warn: (cat: string, data?: Record<string, unknown>) => void;
|
|
5
|
+
error: (cat: string, data?: Record<string, unknown>) => void;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Structured NDJSON logger with explicit levels.
|
|
9
|
+
*
|
|
10
|
+
* Each line is a self-contained JSON object:
|
|
11
|
+
* {"ts":"...","level":"info","cat":"cursor-ok","subcommand":"after-edit",...}
|
|
12
|
+
*
|
|
13
|
+
* Reserved keys: ts, level, cat. All data fields are spread at top level.
|
|
14
|
+
* Parseable with: jq, grep, or any NDJSON-aware tool.
|
|
15
|
+
* Filter examples:
|
|
16
|
+
* jq 'select(.level == "error")'
|
|
17
|
+
* jq 'select(.cat == "cursor-ok")'
|
|
18
|
+
* grep '"cat":"llm-' debug.log | jq .
|
|
19
|
+
*/
|
|
20
|
+
export declare function createLogger(logEnabled: boolean, cwd: string): Logger;
|
|
21
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEjD,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC5D,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC5D,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CAC9D,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAwBrE"}
|
package/dist/notify.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Logger } from "./logger.js";
|
|
2
|
+
export type ContextNotification = {
|
|
3
|
+
message: string;
|
|
4
|
+
timestamp: number;
|
|
5
|
+
};
|
|
6
|
+
export type NotificationManager = {
|
|
7
|
+
addNotification: (sessionID: string | undefined, message: string) => void;
|
|
8
|
+
consumeNotifications: (sessionID: string) => string | null;
|
|
9
|
+
};
|
|
10
|
+
export declare function createNotificationManager(log: Logger, resolveSessionRoot: (sessionID: string | undefined) => string, maxAgeMs?: number): NotificationManager;
|
|
11
|
+
//# sourceMappingURL=notify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notify.d.ts","sourceRoot":"","sources":["../src/notify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,oBAAoB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAC5D,CAAC;AAEF,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,MAAM,EACX,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,EAC7D,QAAQ,SAAU,GACjB,mBAAmB,CAuFrB"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode plugin: GitButler integration via Cursor hook facade.
|
|
3
|
+
*
|
|
4
|
+
* Bridges OpenCode's plugin hooks to GitButler's `but cursor` CLI:
|
|
5
|
+
* - tool.execute.after (edit/write) -> but cursor after-edit
|
|
6
|
+
* - session.idle -> but cursor stop
|
|
7
|
+
* - experimental.chat.messages.transform -> inject pending state notifications
|
|
8
|
+
*
|
|
9
|
+
* This enables automatic branch creation, file-to-branch assignment,
|
|
10
|
+
* and auto-commit when using GitButler workspace mode with OpenCode.
|
|
11
|
+
*
|
|
12
|
+
* Uses Cursor hook format because it has simpler stdin JSON requirements
|
|
13
|
+
* than Claude Code hooks (no transcript_path needed).
|
|
14
|
+
*
|
|
15
|
+
* Multi-agent support: Each OpenCode session gets its own branch via
|
|
16
|
+
* conversation_id isolation in GitButler's session tracking.
|
|
17
|
+
*/
|
|
18
|
+
import type { Plugin } from "@opencode-ai/plugin";
|
|
19
|
+
import type { GitButlerPluginConfig } from "./config.js";
|
|
20
|
+
export declare function createGitButlerPlugin(config?: GitButlerPluginConfig): Plugin;
|
|
21
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAUzD,wBAAgB,qBAAqB,CACnC,MAAM,GAAE,qBAA6C,GACpD,MAAM,CA+nBR"}
|
package/dist/reword.d.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { Logger } from "./logger.js";
|
|
2
|
+
import type { Cli } from "./cli.js";
|
|
3
|
+
import type { BranchOwnership } from "./state.js";
|
|
4
|
+
import type { NotificationManager } from "./notify.js";
|
|
5
|
+
import type { GitButlerPluginConfig } from "./config.js";
|
|
6
|
+
export type RewordDeps = {
|
|
7
|
+
cwd: string;
|
|
8
|
+
log: Logger;
|
|
9
|
+
cli: Cli;
|
|
10
|
+
config: GitButlerPluginConfig;
|
|
11
|
+
defaultBranchPattern: RegExp;
|
|
12
|
+
addNotification: NotificationManager["addNotification"];
|
|
13
|
+
resolveSessionRoot: (sessionID: string | undefined) => string;
|
|
14
|
+
conversationsWithEdits: Set<string>;
|
|
15
|
+
rewordedBranches: Set<string>;
|
|
16
|
+
branchOwnership: Map<string, BranchOwnership>;
|
|
17
|
+
editedFilesPerConversation: Map<string, Set<string>>;
|
|
18
|
+
savePluginState: (conversations: Set<string>, reworded: Set<string>, ownership: Map<string, BranchOwnership>) => Promise<void>;
|
|
19
|
+
internalSessionIds: Set<string>;
|
|
20
|
+
reapStaleLocks: () => void;
|
|
21
|
+
client: {
|
|
22
|
+
session: {
|
|
23
|
+
messages: (opts: {
|
|
24
|
+
path: {
|
|
25
|
+
id: string;
|
|
26
|
+
};
|
|
27
|
+
query: {
|
|
28
|
+
limit: number;
|
|
29
|
+
};
|
|
30
|
+
}) => Promise<{
|
|
31
|
+
data?: Array<{
|
|
32
|
+
info: {
|
|
33
|
+
role: string;
|
|
34
|
+
};
|
|
35
|
+
parts: Array<{
|
|
36
|
+
type: string;
|
|
37
|
+
text?: string;
|
|
38
|
+
}>;
|
|
39
|
+
}>;
|
|
40
|
+
}>;
|
|
41
|
+
create: (opts: {
|
|
42
|
+
body: {
|
|
43
|
+
title: string;
|
|
44
|
+
};
|
|
45
|
+
}) => Promise<{
|
|
46
|
+
data?: {
|
|
47
|
+
id: string;
|
|
48
|
+
};
|
|
49
|
+
}>;
|
|
50
|
+
prompt: (opts: {
|
|
51
|
+
path: {
|
|
52
|
+
id: string;
|
|
53
|
+
};
|
|
54
|
+
body: {
|
|
55
|
+
model: {
|
|
56
|
+
providerID: string;
|
|
57
|
+
modelID: string;
|
|
58
|
+
};
|
|
59
|
+
system: string;
|
|
60
|
+
tools: Record<string, never>;
|
|
61
|
+
parts: Array<{
|
|
62
|
+
type: "text";
|
|
63
|
+
text: string;
|
|
64
|
+
}>;
|
|
65
|
+
};
|
|
66
|
+
}) => Promise<{
|
|
67
|
+
data?: {
|
|
68
|
+
parts: Array<{
|
|
69
|
+
type: string;
|
|
70
|
+
text?: string;
|
|
71
|
+
}>;
|
|
72
|
+
};
|
|
73
|
+
}>;
|
|
74
|
+
delete: (opts: {
|
|
75
|
+
path: {
|
|
76
|
+
id: string;
|
|
77
|
+
};
|
|
78
|
+
}) => Promise<unknown>;
|
|
79
|
+
update: (opts: {
|
|
80
|
+
path: {
|
|
81
|
+
id: string;
|
|
82
|
+
};
|
|
83
|
+
body: {
|
|
84
|
+
title: string;
|
|
85
|
+
};
|
|
86
|
+
}) => Promise<unknown>;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
export declare const COMMIT_PREFIX_PATTERNS: Array<{
|
|
91
|
+
pattern: RegExp;
|
|
92
|
+
prefix: string;
|
|
93
|
+
}>;
|
|
94
|
+
export declare function detectCommitPrefix(text: string): string;
|
|
95
|
+
export declare function toCommitMessage(prompt: string): string;
|
|
96
|
+
export declare function toBranchSlug(prompt: string, maxLength: number): string;
|
|
97
|
+
export type RewordManager = {
|
|
98
|
+
fetchUserPrompt: (sessionID: string) => Promise<string | null>;
|
|
99
|
+
generateLLMCommitMessage: (commitId: string, userPrompt: string) => Promise<string | null>;
|
|
100
|
+
postStopProcessing: (sessionID: string | undefined, conversationId: string, stopFailed?: boolean) => Promise<void>;
|
|
101
|
+
};
|
|
102
|
+
export declare function classifyRewordFailure(stderr: string): string;
|
|
103
|
+
export declare function createRewordManager(deps: RewordDeps): RewordManager;
|
|
104
|
+
//# sourceMappingURL=reword.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reword.d.ts","sourceRoot":"","sources":["../src/reword.ts"],"names":[],"mappings":"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"}
|
package/dist/state.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Logger } from "./logger.js";
|
|
2
|
+
export type HookInput = {
|
|
3
|
+
tool?: string;
|
|
4
|
+
sessionID?: string;
|
|
5
|
+
callID?: string;
|
|
6
|
+
};
|
|
7
|
+
export type HookOutput = {
|
|
8
|
+
title?: string;
|
|
9
|
+
output?: string;
|
|
10
|
+
metadata?: Record<string, unknown>;
|
|
11
|
+
};
|
|
12
|
+
export type EventPayload = Record<string, unknown> & {
|
|
13
|
+
type?: string;
|
|
14
|
+
properties?: Record<string, unknown>;
|
|
15
|
+
};
|
|
16
|
+
export type BranchOwnership = {
|
|
17
|
+
rootSessionID: string;
|
|
18
|
+
branchName: string;
|
|
19
|
+
firstSeen: number;
|
|
20
|
+
};
|
|
21
|
+
export type PluginState = {
|
|
22
|
+
conversationsWithEdits: string[];
|
|
23
|
+
rewordedBranches: string[];
|
|
24
|
+
branchOwnership: Record<string, BranchOwnership>;
|
|
25
|
+
};
|
|
26
|
+
export declare const SUBAGENT_TOOLS: Set<string>;
|
|
27
|
+
export type StateManager = {
|
|
28
|
+
loadPluginState: () => Promise<PluginState>;
|
|
29
|
+
savePluginState: (conversations: Set<string>, reworded: Set<string>, ownership: Map<string, BranchOwnership>) => Promise<void>;
|
|
30
|
+
loadSessionMap: () => Promise<Map<string, string>>;
|
|
31
|
+
saveSessionMap: (map: Map<string, string>) => Promise<void>;
|
|
32
|
+
resolveSessionRoot: (sessionID: string | undefined) => string;
|
|
33
|
+
trackSubagentMapping: (input: HookInput, output?: HookOutput) => Promise<void>;
|
|
34
|
+
trackSessionCreatedMapping: (event: EventPayload) => Promise<void>;
|
|
35
|
+
parentSessionByTaskSession: Map<string, string>;
|
|
36
|
+
};
|
|
37
|
+
export declare function createStateManager(cwd: string, log: Logger): StateManager;
|
|
38
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,sBAAsB,EAAE,MAAM,EAAE,CAAC;IACjC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAClD,CAAC;AAEF,eAAO,MAAM,cAAc,aAIzB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG;IACzB,eAAe,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;IAC5C,eAAe,EAAE,CACf,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,EAC1B,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,EACrB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,KACpC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,cAAc,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,CAAC;IAC9D,oBAAoB,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,0BAA0B,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,0BAA0B,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjD,CAAC;AAEF,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,YAAY,CA6Md"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencode-gitbutler",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "OpenCode plugin for GitButler integration",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "bun build src/index.ts --outdir dist --target bun --format esm && tsc --emitDeclarationOnly",
|
|
16
|
+
"clean": "rm -rf dist",
|
|
17
|
+
"typecheck": "tsc --noEmit",
|
|
18
|
+
"prepublishOnly": "bun run clean && bun run build",
|
|
19
|
+
"postinstall": "node postinstall.mjs",
|
|
20
|
+
"test": "bun test"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"postinstall.mjs",
|
|
25
|
+
"skill",
|
|
26
|
+
"command"
|
|
27
|
+
],
|
|
28
|
+
"keywords": [
|
|
29
|
+
"opencode",
|
|
30
|
+
"plugin",
|
|
31
|
+
"gitbutler",
|
|
32
|
+
"git",
|
|
33
|
+
"branches",
|
|
34
|
+
"ai"
|
|
35
|
+
],
|
|
36
|
+
"author": "gaboe",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/gaboe/opencode-gitbutler.git"
|
|
41
|
+
},
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/gaboe/opencode-gitbutler/issues"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/gaboe/opencode-gitbutler#readme",
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@opencode-ai/plugin": "^1.1.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@opencode-ai/plugin": ">=1.1.0"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/bun": "^1.3.8",
|
|
54
|
+
"typescript": "^5.3.0"
|
|
55
|
+
}
|
|
56
|
+
}
|
package/postinstall.mjs
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execSync } from "child_process";
|
|
4
|
+
|
|
5
|
+
try {
|
|
6
|
+
execSync("but --version", { stdio: "pipe" });
|
|
7
|
+
console.log("✓ GitButler CLI found");
|
|
8
|
+
} catch {
|
|
9
|
+
console.warn("⚠ GitButler CLI not found. Install with: brew install gitbutler");
|
|
10
|
+
}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: but
|
|
3
|
+
version: 0.19.0
|
|
4
|
+
description: Commit, push, branch, and manage version control. Use for git commit, git status, git push, git diff, creating branches, staging files, editing history, pull requests, or any git/version control operation. Replaces git write commands with 'but' - always use this instead of raw git.
|
|
5
|
+
author: GitButler Team
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# GitButler CLI Skill
|
|
9
|
+
|
|
10
|
+
Help users work with GitButler CLI (`but` command) in workspace mode.
|
|
11
|
+
|
|
12
|
+
## New Session Workflow
|
|
13
|
+
|
|
14
|
+
**EVERY new agent session that involves code changes MUST follow this flow:**
|
|
15
|
+
|
|
16
|
+
1. **Sync first** → `but pull` to get latest upstream changes (prevents conflicts and stale base)
|
|
17
|
+
2. **Check state** → `but status` to see existing branches and unstaged changes
|
|
18
|
+
3. **Decide branch** →
|
|
19
|
+
- If an existing branch matches the task → reuse it (it's already applied)
|
|
20
|
+
- If this is new work → `but branch new <task-name>` (e.g. `feat/add-auth`, `fix/login-bug`)
|
|
21
|
+
- If you need to resume unapplied work → `but apply <branch>`
|
|
22
|
+
4. **Make changes** → Edit files as needed
|
|
23
|
+
5. **Stage & commit** → `but commit <branch> -m "message" --changes <id>,<id>`
|
|
24
|
+
6. **Refine** → Use `but absorb` or `but squash` to clean up history
|
|
25
|
+
7. **Push when ready** → `but push <branch>`
|
|
26
|
+
8. **Create PR** → `but pr new <branch> -t` (uses default target branch)
|
|
27
|
+
|
|
28
|
+
**Branch naming**: Use conventional prefixes: `feat/`, `fix/`, `chore/`, `refactor/`
|
|
29
|
+
|
|
30
|
+
**Commit early, commit often.** Don't hesitate to create commits - GitButler makes editing history trivial. You can always `squash`, `reword`, or `absorb` changes into existing commits later. Small atomic commits are better than large uncommitted changes.
|
|
31
|
+
|
|
32
|
+
## After Using Write/Edit Tools
|
|
33
|
+
|
|
34
|
+
When ready to commit:
|
|
35
|
+
|
|
36
|
+
1. Run `but status --json` to see uncommitted changes and get their CLI IDs
|
|
37
|
+
2. Commit the relevant files directly: `but commit <branch> -m "message" --changes <id>,<id>`
|
|
38
|
+
|
|
39
|
+
You can batch multiple file edits before committing - no need to commit after every single change.
|
|
40
|
+
|
|
41
|
+
## Critical Concept: Workspace Model
|
|
42
|
+
|
|
43
|
+
**GitButler ≠ Traditional Git**
|
|
44
|
+
|
|
45
|
+
- **Traditional Git**: One branch at a time, switch with `git checkout`
|
|
46
|
+
- **GitButler**: Multiple stacks simultaneously in one workspace, changes assigned to stacks
|
|
47
|
+
|
|
48
|
+
**This means:**
|
|
49
|
+
|
|
50
|
+
- ❌ Don't use `git status`, `git commit`, `git checkout`
|
|
51
|
+
- ✅ Use `but status`, `but commit`, `but` commands
|
|
52
|
+
- ✅ Read-only git commands are fine (`git log`, `git diff`)
|
|
53
|
+
|
|
54
|
+
## Hard Safety Rules (Non-Negotiable)
|
|
55
|
+
|
|
56
|
+
1. **Never discard changes you did not create.**
|
|
57
|
+
- `zz` (unassigned) often contains work from other sessions/agents/users.
|
|
58
|
+
- If unrelated changes exist, leave them untouched and ask before any discard action.
|
|
59
|
+
2. **Never leave your own changes in `zz` at the end of work.**
|
|
60
|
+
- After edits, run `but status --json` and move your file/hunk IDs to the correct branch via `but stage` or `but commit --changes`.
|
|
61
|
+
3. **Validate branch ownership before commit.**
|
|
62
|
+
- Confirm each changed file/hunk belongs to the intended branch/task, then commit only those IDs.
|
|
63
|
+
|
|
64
|
+
## Quick Start
|
|
65
|
+
|
|
66
|
+
**Installation:**
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
curl -sSL https://gitbutler.com/install.sh | sh
|
|
70
|
+
but setup # Initialize in your repo
|
|
71
|
+
but skill install --path <path> # Install/update skill (agents use --path with known location)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Note for AI agents:**
|
|
75
|
+
- When installing or updating this skill programmatically, always use `--path` to specify the exact installation directory. The `--detect` flag requires user interaction if multiple installations exist.
|
|
76
|
+
- **Use `--json` flag for all commands** to get structured, parseable output. This is especially important for `but status --json` to reliably parse workspace state.
|
|
77
|
+
|
|
78
|
+
**Core workflow:**
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
but status --json # Always start here - shows workspace state (JSON for agents)
|
|
82
|
+
but branch new feature # Create new stack for work
|
|
83
|
+
# Make changes...
|
|
84
|
+
but commit <branch> -m "…" --changes <id>,<id> # Commit specific files by CLI ID
|
|
85
|
+
but push <branch> # Push to remote
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Essential Commands
|
|
89
|
+
|
|
90
|
+
For detailed command syntax and all available options, see [references/reference.md](references/reference.md).
|
|
91
|
+
For a hands-on learning guide, see [references/tutorial.md](references/tutorial.md).
|
|
92
|
+
For a one-page quick lookup, see [references/cheatsheet.md](references/cheatsheet.md).
|
|
93
|
+
|
|
94
|
+
**IMPORTANT for AI agents:** Add `--json` flag to all commands for structured, parseable output.
|
|
95
|
+
|
|
96
|
+
**Understanding state:**
|
|
97
|
+
|
|
98
|
+
- `but status --json` - Overview (START HERE, always use --json for agents)
|
|
99
|
+
- `but status --json -f` - Overview with full file lists (use when you need to see all changed files)
|
|
100
|
+
- `but show <id> --json` - Details about commit/branch
|
|
101
|
+
- `but diff <id>` - Show diff
|
|
102
|
+
|
|
103
|
+
**Flags explanation:**
|
|
104
|
+
- `--json` - Output structured JSON instead of human-readable text (always use for agents)
|
|
105
|
+
- `-f` - Include detailed file lists in status output (combines with --json: `but status --json -f`)
|
|
106
|
+
|
|
107
|
+
**Organizing work:**
|
|
108
|
+
|
|
109
|
+
- `but branch new <name>` - Independent branch
|
|
110
|
+
- `but branch new <name> -a <anchor>` - Stacked branch (dependent)
|
|
111
|
+
- `but stage <file> <branch>` - Pre-assign file to branch (optional, for organizing before commit)
|
|
112
|
+
|
|
113
|
+
**Making changes:**
|
|
114
|
+
|
|
115
|
+
- `but commit <branch> -m "msg" --changes <id>,<id>` - Commit specific files or hunks (recommended)
|
|
116
|
+
- `but commit <branch> -m "msg" -p <id>,<id>` - Same as above, using short flag
|
|
117
|
+
- `but commit <branch> -m "msg"` - Commit ALL uncommitted changes to branch
|
|
118
|
+
- `but commit <branch> --only -m "msg"` - Commit only pre-staged changes (cannot combine with --changes)
|
|
119
|
+
- `but amend <file-id> <commit-id>` - Amend file into specific commit (explicit control)
|
|
120
|
+
- `but absorb <file-id>` - Absorb file into auto-detected commit (smart matching)
|
|
121
|
+
- `but absorb <branch-id>` - Absorb all changes staged to a branch
|
|
122
|
+
- `but absorb` - Absorb ALL uncommitted changes (use with caution)
|
|
123
|
+
|
|
124
|
+
**Getting IDs for --changes:**
|
|
125
|
+
- **File IDs**: `but status --json` - commit entire files
|
|
126
|
+
- **Hunk IDs**: `but diff --json` - commit individual hunks (for fine-grained control when a file has multiple changes)
|
|
127
|
+
|
|
128
|
+
**Editing history:**
|
|
129
|
+
|
|
130
|
+
- `but rub <source> <dest>` - Universal edit (stage/amend/squash/move)
|
|
131
|
+
- `but squash <commits>` - Combine commits
|
|
132
|
+
- `but reword <id>` - Change commit message/branch name
|
|
133
|
+
|
|
134
|
+
**Remote operations:**
|
|
135
|
+
|
|
136
|
+
- `but pull` - Update with upstream
|
|
137
|
+
- `but push [branch]` - Push to remote
|
|
138
|
+
- `but pr new <branch>` - Push and create pull request (auto-pushes, no need to push first)
|
|
139
|
+
- `but pr new <branch> -m "Title..."` - Inline PR message (first line is title, rest is description)
|
|
140
|
+
- `but pr new <branch> -F pr_message.txt` - PR message from file (first line is title, rest is description)
|
|
141
|
+
- For stacked branches, the custom message (`-m` or `-F`) only applies to the selected branch; dependent branches use defaults
|
|
142
|
+
|
|
143
|
+
## Key Concepts
|
|
144
|
+
|
|
145
|
+
For deeper understanding of the workspace model, dependency tracking, and philosophy, see [references/concepts.md](references/concepts.md).
|
|
146
|
+
|
|
147
|
+
**CLI IDs**: Every object gets a short ID (e.g., `c5` for commit, `bu` for branch). Use these as arguments.
|
|
148
|
+
|
|
149
|
+
**Parallel vs Stacked branches**:
|
|
150
|
+
|
|
151
|
+
- Parallel: Independent work that doesn't depend on each other
|
|
152
|
+
- Stacked: Dependent work where one feature builds on another
|
|
153
|
+
|
|
154
|
+
**The `but rub` primitive**: Core operation that does different things based on what you combine:
|
|
155
|
+
|
|
156
|
+
- File + Branch → Stage
|
|
157
|
+
- File + Commit → Amend
|
|
158
|
+
- Commit + Commit → Squash
|
|
159
|
+
- Commit + Branch → Move
|
|
160
|
+
|
|
161
|
+
## Workflow Examples
|
|
162
|
+
|
|
163
|
+
For complete step-by-step workflows and real-world scenarios, see [references/examples.md](references/examples.md).
|
|
164
|
+
|
|
165
|
+
**Starting independent work:**
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
but status --json
|
|
169
|
+
but branch new api-endpoint
|
|
170
|
+
but branch new ui-update
|
|
171
|
+
# Make changes, then commit specific files to appropriate branches
|
|
172
|
+
but status --json # Get file CLI IDs
|
|
173
|
+
but commit api-endpoint -m "Add endpoint" --changes <api-file-id>
|
|
174
|
+
but commit ui-update -m "Update UI" --changes <ui-file-id>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Committing specific hunks (fine-grained control):**
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
but diff --json # See hunk IDs when a file has multiple changes
|
|
181
|
+
but commit <branch> -m "Fix first issue" --changes <hunk-id-1>
|
|
182
|
+
but commit <branch> -m "Fix second issue" --changes <hunk-id-2>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Cleaning up commits:**
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
but absorb # Auto-amend changes
|
|
189
|
+
but status --json # Verify absorb result
|
|
190
|
+
but squash <branch> # Squash all commits in branch
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Resolving conflicts:**
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
but resolve <commit> # Enter resolution mode
|
|
197
|
+
# Fix conflicts in editor
|
|
198
|
+
but resolve finish # Complete resolution
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Managing workspace:**
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
but config target origin/test # Set default PR target (requires unapply all branches first)
|
|
205
|
+
but unapply <branch> # Remove branch from workspace (keeps commits)
|
|
206
|
+
but apply <branch> # Bring branch back into workspace
|
|
207
|
+
but teardown # Exit GitButler mode → normal git
|
|
208
|
+
but setup # Re-enter GitButler mode
|
|
209
|
+
but discard <ids> # Discard unstaged changes
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Post-Merge PR Flow
|
|
213
|
+
|
|
214
|
+
After a PR is squash-merged on GitHub, follow this exact sequence:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
but unapply <merged-branch> # MUST do BEFORE pull - prevents orphan branch errors
|
|
218
|
+
but pull # Pull merged changes from remote
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Critical**: If you `but pull` before unapplying the merged branch, GitButler will error with orphan branch conflicts. Always unapply first.
|
|
222
|
+
|
|
223
|
+
**If `but unapply` fails** (branch already gone from workspace after remote deletion with `--delete-branch`), `but pull` may also fail with "resolution mismatch" errors because the ghost stack still exists internally. In this case, the GitButler desktop app can handle it — tell the user to run `but pull` from the GUI. Alternatively, use `but teardown` → `but setup` → `but config target origin/<branch>` to reset.
|
|
224
|
+
|
|
225
|
+
**After `but teardown` → `but setup`**: Target config resets. Run `but config target origin/<branch>` again.
|
|
226
|
+
|
|
227
|
+
## Using `--no-hooks` Safely
|
|
228
|
+
|
|
229
|
+
When pre-commit hooks fail on pre-existing errors unrelated to your changes, use `--no-hooks`. But this skips the formatter too:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
bun run format # Format FIRST
|
|
233
|
+
but commit <branch> -m "msg" --changes <ids> --no-hooks # Then commit without hooks
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Alternatively, commit normally and absorb formatter fixes:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
but commit <branch> -m "msg" --changes <ids> # Commit (hooks may fix formatting)
|
|
240
|
+
but absorb # Absorb any auto-formatted changes
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Known Issues & Workarounds
|
|
244
|
+
|
|
245
|
+
| Issue | What happens | Workaround |
|
|
246
|
+
|-------|-------------|------------|
|
|
247
|
+
| `but resolve` loses target config | After entering resolve mode, `but config target` resets to "not set" | Run `but config target origin/<branch>` again after `but resolve finish`. If finish fails, do `git checkout gitbutler/workspace` → `but teardown` → `but setup` |
|
|
248
|
+
| `but absorb` hunk lock | Absorb assigns hunk to wrong commit when it's locked by another commit on a different branch | Use `but amend <file> <commit>` for explicit control instead of absorb |
|
|
249
|
+
| `but pr new` has no `--base` flag | Always creates PR against default target | Set target first: `but config target origin/<branch>` |
|
|
250
|
+
| `but config target` requires unapply | Cannot change target with applied branches | `but unapply` all → change target → `but apply` |
|
|
251
|
+
| `but config forge auth` is interactive | Cannot run in non-interactive agent mode | User must run in terminal + grant org access on GitHub |
|
|
252
|
+
| `but commit` pre-commit hook fails | Hook fails on pre-existing errors unrelated to your changes | `but commit --no-hooks` if errors are not from your changes. **Always `bun run format` first** since `--no-hooks` skips the formatter |
|
|
253
|
+
| `but branch delete` last segment | Cannot delete if it would leave anonymous segment | Use `but unapply` instead of delete |
|
|
254
|
+
| `but stage` prefix matching | Branch name can be abbreviated | `but stage <id> ch` works for `chore/gitbutler-setup` |
|
|
255
|
+
| `but discard` hunk range error | Discarding file-level changes sometimes fails with hunk range errors | Use `git checkout -- <file>` instead of `but discard` for file-level discards |
|
|
256
|
+
| `but teardown` + `but setup` resets target | After teardown/setup cycle, target config is lost | Run `but config target origin/<branch>` again after setup |
|
|
257
|
+
| Lefthook `pre-commit.old` accumulates | Lefthook creates `pre-commit.old` backup that conflicts on next install | Add `rm -f .git/hooks/pre-commit.old` to `prepare` script in package.json |
|
|
258
|
+
| `but pull` before unapply | Pulling with merged branches still applied causes orphan errors | **Always** `but unapply <merged-branch>` before `but pull` |
|
|
259
|
+
| `but unapply` after remote branch deletion | `but unapply` fails with "branch not found" when remote deleted the branch (e.g. `--delete-branch` on merge), and subsequent `but pull` fails with "resolution mismatch" | Use GitButler desktop app to pull, or `but teardown` → `but setup` → `but config target origin/<branch>` |
|
|
260
|
+
|
|
261
|
+
## Critical Safety Rules
|
|
262
|
+
|
|
263
|
+
1. **NEVER discard changes you didn't create.** Unassigned changes in `zz` may belong to other agents, sessions, or the user. Always ask the user before running `but discard` or `git checkout --` on any change you don't recognize. In GitButler workspace, multiple actors work in parallel — discarding "stale" or "already merged" changes is a destructive assumption.
|
|
264
|
+
2. **Always assign your changes to a branch immediately.** Don't leave edits sitting in `zz` (unassigned). After editing files, stage them to your working branch with `but stage <file-id> <branch>` or commit directly with `--changes`.
|
|
265
|
+
|
|
266
|
+
## Guidelines
|
|
267
|
+
|
|
268
|
+
1. Always start with `but status --json` to understand current state (agents should always use `--json`)
|
|
269
|
+
2. Create a new stack for each independent work theme
|
|
270
|
+
3. Use `--changes` to commit specific files directly - no need to stage first
|
|
271
|
+
4. **Commit early and often** - don't wait for perfection. Unlike traditional git, GitButler makes editing history trivial with `absorb`, `squash`, and `reword`. It's better to have small, atomic commits that you refine later than to accumulate large uncommitted changes.
|
|
272
|
+
5. **Use `--json` flag for ALL commands** when running as an agent - this provides structured, parseable output instead of human-readable text
|
|
273
|
+
6. Use `--dry-run` flags (push, absorb) when unsure
|
|
274
|
+
7. **Run `but pull` frequently** — at session start, before creating branches, and before pushing. Stale workspace = merge conflicts
|
|
275
|
+
8. When updating this skill, use `but skill install --path <known-path>` to avoid prompts
|