@pruddiman/hem 0.0.1-beta-5671db0
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/dist/agents/arbiter-agent.d.ts +72 -0
- package/dist/agents/arbiter-agent.js +149 -0
- package/dist/agents/architecture-agent.d.ts +148 -0
- package/dist/agents/architecture-agent.js +459 -0
- package/dist/agents/base-agent.d.ts +44 -0
- package/dist/agents/base-agent.js +57 -0
- package/dist/agents/crossref-agent.d.ts +140 -0
- package/dist/agents/crossref-agent.js +560 -0
- package/dist/agents/crossref-arbiter-agent.d.ts +72 -0
- package/dist/agents/crossref-arbiter-agent.js +147 -0
- package/dist/agents/documentation-agent.d.ts +55 -0
- package/dist/agents/documentation-agent.js +159 -0
- package/dist/agents/exploration-agent.d.ts +58 -0
- package/dist/agents/exploration-agent.js +102 -0
- package/dist/agents/grouping-agent.d.ts +167 -0
- package/dist/agents/grouping-agent.js +557 -0
- package/dist/agents/index-agent.d.ts +86 -0
- package/dist/agents/index-agent.js +360 -0
- package/dist/agents/organization-agent.d.ts +144 -0
- package/dist/agents/organization-agent.js +607 -0
- package/dist/auth.d.ts +372 -0
- package/dist/auth.js +1072 -0
- package/dist/broadcast-mcp.d.ts +21 -0
- package/dist/broadcast-mcp.js +59 -0
- package/dist/changelog.d.ts +85 -0
- package/dist/changelog.js +223 -0
- package/dist/decision-queue.d.ts +173 -0
- package/dist/decision-queue.js +265 -0
- package/dist/diff-scope.d.ts +24 -0
- package/dist/diff-scope.js +28 -0
- package/dist/discovery.d.ts +54 -0
- package/dist/discovery.js +405 -0
- package/dist/grouping.d.ts +37 -0
- package/dist/grouping.js +343 -0
- package/dist/helpers/format.d.ts +5 -0
- package/dist/helpers/format.js +13 -0
- package/dist/helpers/index.d.ts +11 -0
- package/dist/helpers/index.js +11 -0
- package/dist/helpers/parsing.d.ts +52 -0
- package/dist/helpers/parsing.js +128 -0
- package/dist/helpers/paths.d.ts +41 -0
- package/dist/helpers/paths.js +67 -0
- package/dist/helpers/strings.d.ts +45 -0
- package/dist/helpers/strings.js +97 -0
- package/dist/index.d.ts +135 -0
- package/dist/index.js +1087 -0
- package/dist/merge-utils.d.ts +22 -0
- package/dist/merge-utils.js +34 -0
- package/dist/orchestrator.d.ts +194 -0
- package/dist/orchestrator.js +1169 -0
- package/dist/output.d.ts +106 -0
- package/dist/output.js +243 -0
- package/dist/progress.d.ts +228 -0
- package/dist/progress.js +644 -0
- package/dist/providers/copilot.d.ts +247 -0
- package/dist/providers/copilot.js +598 -0
- package/dist/providers/index.d.ts +15 -0
- package/dist/providers/index.js +12 -0
- package/dist/providers/opencode.d.ts +156 -0
- package/dist/providers/opencode.js +416 -0
- package/dist/providers/types.d.ts +156 -0
- package/dist/providers/types.js +16 -0
- package/dist/resources.d.ts +76 -0
- package/dist/resources.js +151 -0
- package/dist/search-index.d.ts +71 -0
- package/dist/search-index.js +187 -0
- package/dist/search-mcp.d.ts +25 -0
- package/dist/search-mcp.js +100 -0
- package/dist/server-utils.d.ts +56 -0
- package/dist/server-utils.js +135 -0
- package/dist/session.d.ts +227 -0
- package/dist/session.js +370 -0
- package/dist/types.d.ts +272 -0
- package/dist/types.js +5 -0
- package/dist/worktree.d.ts +82 -0
- package/dist/worktree.js +187 -0
- package/package.json +45 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git worktree utilities for the --worktree flag.
|
|
3
|
+
*
|
|
4
|
+
* Creates an isolated git worktree under `.hem/worktree/` on a fresh branch,
|
|
5
|
+
* runs the pipeline there, then commits and pushes the branch for review.
|
|
6
|
+
*
|
|
7
|
+
* All functions use execSync (same pattern as changelog.ts).
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Returns the absolute path to the root of the git repository containing `cwd`.
|
|
11
|
+
*
|
|
12
|
+
* @throws If `cwd` is not inside a git repository.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getRepoRoot(cwd: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Returns the name of the currently checked-out branch.
|
|
17
|
+
*
|
|
18
|
+
* @param repoRoot - Absolute path to the git repository root.
|
|
19
|
+
* @throws If the repo is in a detached HEAD state or git is unavailable.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getCurrentBranch(repoRoot: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Generates a unique worktree branch name based on the current branch and a
|
|
24
|
+
* timestamp.
|
|
25
|
+
*
|
|
26
|
+
* Format: `hem/<sanitized-base>-<YYYYMMDD-HHmmss>`
|
|
27
|
+
*
|
|
28
|
+
* The base branch name is sanitized to be a valid git ref component:
|
|
29
|
+
* slashes and non-alphanumeric characters (except `-`) are replaced with `-`,
|
|
30
|
+
* and leading/trailing dashes are removed.
|
|
31
|
+
*
|
|
32
|
+
* @param baseBranch - The currently checked-out branch name.
|
|
33
|
+
*/
|
|
34
|
+
export declare function generateWorktreeBranch(baseBranch: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Ensures `pattern` appears in `<repoRoot>/.gitignore`.
|
|
37
|
+
*
|
|
38
|
+
* If the file does not exist it is created. If the pattern is already present
|
|
39
|
+
* (exact line match) this is a no-op.
|
|
40
|
+
*
|
|
41
|
+
* @param repoRoot - Absolute path to the git repository root.
|
|
42
|
+
* @param pattern - The gitignore pattern to add (e.g. `.hem/worktree/`).
|
|
43
|
+
*/
|
|
44
|
+
export declare function ensureGitignored(repoRoot: string, pattern: string): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Creates a git worktree at `.hem/worktree/` inside `repoRoot` checked out on
|
|
47
|
+
* a new branch `branchName`.
|
|
48
|
+
*
|
|
49
|
+
* If `.hem/worktree/` already exists (from a previous interrupted run), it is
|
|
50
|
+
* forcibly removed first.
|
|
51
|
+
*
|
|
52
|
+
* @param repoRoot - Absolute path to the git repository root.
|
|
53
|
+
* @param branchName - New branch name to create (e.g. `hem/main-20260322-143000`).
|
|
54
|
+
* @returns Absolute path to the created worktree directory.
|
|
55
|
+
*/
|
|
56
|
+
export declare function setupWorktree(repoRoot: string, branchName: string): string;
|
|
57
|
+
/**
|
|
58
|
+
* Stages all changes in the worktree and creates a commit.
|
|
59
|
+
*
|
|
60
|
+
* If there are no changes to commit (clean working tree) this is a no-op.
|
|
61
|
+
*
|
|
62
|
+
* @param worktreePath - Absolute path to the worktree directory.
|
|
63
|
+
* @param message - Commit message.
|
|
64
|
+
*/
|
|
65
|
+
export declare function commitWorktree(worktreePath: string, message: string): void;
|
|
66
|
+
/**
|
|
67
|
+
* Pushes `branchName` from the worktree to `origin`.
|
|
68
|
+
*
|
|
69
|
+
* @param worktreePath - Absolute path to the worktree directory.
|
|
70
|
+
* @param branchName - Branch to push (e.g. `hem/main-20260322-143000`).
|
|
71
|
+
*/
|
|
72
|
+
export declare function pushWorktree(worktreePath: string, branchName: string): void;
|
|
73
|
+
/**
|
|
74
|
+
* Removes the worktree at `worktreePath` from the git worktree list and deletes
|
|
75
|
+
* its directory.
|
|
76
|
+
*
|
|
77
|
+
* This is best-effort — errors are swallowed so cleanup never aborts the run.
|
|
78
|
+
*
|
|
79
|
+
* @param repoRoot - Absolute path to the git repository root.
|
|
80
|
+
* @param worktreePath - Absolute path to the worktree directory.
|
|
81
|
+
*/
|
|
82
|
+
export declare function cleanupWorktree(repoRoot: string, worktreePath: string): void;
|
package/dist/worktree.js
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git worktree utilities for the --worktree flag.
|
|
3
|
+
*
|
|
4
|
+
* Creates an isolated git worktree under `.hem/worktree/` on a fresh branch,
|
|
5
|
+
* runs the pipeline there, then commits and pushes the branch for review.
|
|
6
|
+
*
|
|
7
|
+
* All functions use execSync (same pattern as changelog.ts).
|
|
8
|
+
*/
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
11
|
+
import { execSync } from "node:child_process";
|
|
12
|
+
// ── Repo helpers ───────────────────────────────────────────────────────
|
|
13
|
+
/**
|
|
14
|
+
* Returns the absolute path to the root of the git repository containing `cwd`.
|
|
15
|
+
*
|
|
16
|
+
* @throws If `cwd` is not inside a git repository.
|
|
17
|
+
*/
|
|
18
|
+
export function getRepoRoot(cwd) {
|
|
19
|
+
return execSync("git rev-parse --show-toplevel", {
|
|
20
|
+
cwd,
|
|
21
|
+
encoding: "utf-8",
|
|
22
|
+
timeout: 5_000,
|
|
23
|
+
}).trim();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Returns the name of the currently checked-out branch.
|
|
27
|
+
*
|
|
28
|
+
* @param repoRoot - Absolute path to the git repository root.
|
|
29
|
+
* @throws If the repo is in a detached HEAD state or git is unavailable.
|
|
30
|
+
*/
|
|
31
|
+
export function getCurrentBranch(repoRoot) {
|
|
32
|
+
return execSync("git rev-parse --abbrev-ref HEAD", {
|
|
33
|
+
cwd: repoRoot,
|
|
34
|
+
encoding: "utf-8",
|
|
35
|
+
timeout: 5_000,
|
|
36
|
+
}).trim();
|
|
37
|
+
}
|
|
38
|
+
// ── Branch naming ──────────────────────────────────────────────────────
|
|
39
|
+
/**
|
|
40
|
+
* Generates a unique worktree branch name based on the current branch and a
|
|
41
|
+
* timestamp.
|
|
42
|
+
*
|
|
43
|
+
* Format: `hem/<sanitized-base>-<YYYYMMDD-HHmmss>`
|
|
44
|
+
*
|
|
45
|
+
* The base branch name is sanitized to be a valid git ref component:
|
|
46
|
+
* slashes and non-alphanumeric characters (except `-`) are replaced with `-`,
|
|
47
|
+
* and leading/trailing dashes are removed.
|
|
48
|
+
*
|
|
49
|
+
* @param baseBranch - The currently checked-out branch name.
|
|
50
|
+
*/
|
|
51
|
+
export function generateWorktreeBranch(baseBranch) {
|
|
52
|
+
const sanitized = baseBranch
|
|
53
|
+
.replace(/[^a-zA-Z0-9-]/g, "-")
|
|
54
|
+
.replace(/-+/g, "-")
|
|
55
|
+
.replace(/^-|-$/g, "");
|
|
56
|
+
const now = new Date();
|
|
57
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
58
|
+
const datePart = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}`;
|
|
59
|
+
const timePart = `${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
|
|
60
|
+
return `hem/${sanitized}-${datePart}-${timePart}`;
|
|
61
|
+
}
|
|
62
|
+
// ── .gitignore ─────────────────────────────────────────────────────────
|
|
63
|
+
/**
|
|
64
|
+
* Ensures `pattern` appears in `<repoRoot>/.gitignore`.
|
|
65
|
+
*
|
|
66
|
+
* If the file does not exist it is created. If the pattern is already present
|
|
67
|
+
* (exact line match) this is a no-op.
|
|
68
|
+
*
|
|
69
|
+
* @param repoRoot - Absolute path to the git repository root.
|
|
70
|
+
* @param pattern - The gitignore pattern to add (e.g. `.hem/worktree/`).
|
|
71
|
+
*/
|
|
72
|
+
export async function ensureGitignored(repoRoot, pattern) {
|
|
73
|
+
const gitignorePath = join(repoRoot, ".gitignore");
|
|
74
|
+
let content = "";
|
|
75
|
+
try {
|
|
76
|
+
content = await readFile(gitignorePath, "utf-8");
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// File doesn't exist — will be created below
|
|
80
|
+
}
|
|
81
|
+
const lines = content.split("\n");
|
|
82
|
+
if (lines.some((line) => line.trim() === pattern)) {
|
|
83
|
+
return; // Already present
|
|
84
|
+
}
|
|
85
|
+
const newContent = content.length > 0 && !content.endsWith("\n")
|
|
86
|
+
? `${content}\n${pattern}\n`
|
|
87
|
+
: `${content}${pattern}\n`;
|
|
88
|
+
await writeFile(gitignorePath, newContent, "utf-8");
|
|
89
|
+
}
|
|
90
|
+
// ── Worktree lifecycle ─────────────────────────────────────────────────
|
|
91
|
+
/**
|
|
92
|
+
* Creates a git worktree at `.hem/worktree/` inside `repoRoot` checked out on
|
|
93
|
+
* a new branch `branchName`.
|
|
94
|
+
*
|
|
95
|
+
* If `.hem/worktree/` already exists (from a previous interrupted run), it is
|
|
96
|
+
* forcibly removed first.
|
|
97
|
+
*
|
|
98
|
+
* @param repoRoot - Absolute path to the git repository root.
|
|
99
|
+
* @param branchName - New branch name to create (e.g. `hem/main-20260322-143000`).
|
|
100
|
+
* @returns Absolute path to the created worktree directory.
|
|
101
|
+
*/
|
|
102
|
+
export function setupWorktree(repoRoot, branchName) {
|
|
103
|
+
const worktreePath = join(repoRoot, ".hem", "worktree");
|
|
104
|
+
// Remove stale worktree if present
|
|
105
|
+
try {
|
|
106
|
+
execSync(`git worktree remove "${worktreePath}" --force`, {
|
|
107
|
+
cwd: repoRoot,
|
|
108
|
+
encoding: "utf-8",
|
|
109
|
+
timeout: 15_000,
|
|
110
|
+
stdio: "pipe",
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Didn't exist — that's fine
|
|
115
|
+
}
|
|
116
|
+
execSync(`git worktree add "${worktreePath}" -b "${branchName}"`, {
|
|
117
|
+
cwd: repoRoot,
|
|
118
|
+
encoding: "utf-8",
|
|
119
|
+
timeout: 30_000,
|
|
120
|
+
});
|
|
121
|
+
return worktreePath;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Stages all changes in the worktree and creates a commit.
|
|
125
|
+
*
|
|
126
|
+
* If there are no changes to commit (clean working tree) this is a no-op.
|
|
127
|
+
*
|
|
128
|
+
* @param worktreePath - Absolute path to the worktree directory.
|
|
129
|
+
* @param message - Commit message.
|
|
130
|
+
*/
|
|
131
|
+
export function commitWorktree(worktreePath, message) {
|
|
132
|
+
// Stage everything
|
|
133
|
+
execSync("git add -A", {
|
|
134
|
+
cwd: worktreePath,
|
|
135
|
+
encoding: "utf-8",
|
|
136
|
+
timeout: 15_000,
|
|
137
|
+
});
|
|
138
|
+
// Check if there's anything to commit
|
|
139
|
+
const status = execSync("git status --porcelain", {
|
|
140
|
+
cwd: worktreePath,
|
|
141
|
+
encoding: "utf-8",
|
|
142
|
+
timeout: 10_000,
|
|
143
|
+
}).trim();
|
|
144
|
+
if (status.length === 0) {
|
|
145
|
+
return; // Nothing to commit
|
|
146
|
+
}
|
|
147
|
+
execSync(`git commit -m "${message.replace(/"/g, '\\"')}"`, {
|
|
148
|
+
cwd: worktreePath,
|
|
149
|
+
encoding: "utf-8",
|
|
150
|
+
timeout: 30_000,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Pushes `branchName` from the worktree to `origin`.
|
|
155
|
+
*
|
|
156
|
+
* @param worktreePath - Absolute path to the worktree directory.
|
|
157
|
+
* @param branchName - Branch to push (e.g. `hem/main-20260322-143000`).
|
|
158
|
+
*/
|
|
159
|
+
export function pushWorktree(worktreePath, branchName) {
|
|
160
|
+
execSync(`git push origin "${branchName}"`, {
|
|
161
|
+
cwd: worktreePath,
|
|
162
|
+
encoding: "utf-8",
|
|
163
|
+
timeout: 60_000,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Removes the worktree at `worktreePath` from the git worktree list and deletes
|
|
168
|
+
* its directory.
|
|
169
|
+
*
|
|
170
|
+
* This is best-effort — errors are swallowed so cleanup never aborts the run.
|
|
171
|
+
*
|
|
172
|
+
* @param repoRoot - Absolute path to the git repository root.
|
|
173
|
+
* @param worktreePath - Absolute path to the worktree directory.
|
|
174
|
+
*/
|
|
175
|
+
export function cleanupWorktree(repoRoot, worktreePath) {
|
|
176
|
+
try {
|
|
177
|
+
execSync(`git worktree remove "${worktreePath}" --force`, {
|
|
178
|
+
cwd: repoRoot,
|
|
179
|
+
encoding: "utf-8",
|
|
180
|
+
timeout: 15_000,
|
|
181
|
+
stdio: "pipe",
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
// Best-effort — ignore errors
|
|
186
|
+
}
|
|
187
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pruddiman/hem",
|
|
3
|
+
"version": "0.0.1-beta-5671db0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"hem": "./dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=20.0.0"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"start": "tsc && node ./dist/index.js",
|
|
17
|
+
"test": "vitest run",
|
|
18
|
+
"test:watch": "vitest",
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
20
|
+
"lint": "tsc --noEmit",
|
|
21
|
+
"publish:beta": "node scripts/publish-beta.mjs"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@github/copilot-sdk": "^0.2.2",
|
|
25
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
26
|
+
"@opencode-ai/sdk": "^1.14.19",
|
|
27
|
+
"better-sqlite3": "^12.8.0",
|
|
28
|
+
"commander": "^14.0.3",
|
|
29
|
+
"fast-glob": "^3.3.3",
|
|
30
|
+
"ink": "^6.7.0",
|
|
31
|
+
"ink-spinner": "^5.0.0",
|
|
32
|
+
"p-limit": "^7.3.0",
|
|
33
|
+
"react": "^19.2.4",
|
|
34
|
+
"vectra": "^0.12.3"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
38
|
+
"@types/node": "^25.2.3",
|
|
39
|
+
"@types/react": "^19.2.14",
|
|
40
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
41
|
+
"ink-testing-library": "^4.0.0",
|
|
42
|
+
"typescript": "^5.9.3",
|
|
43
|
+
"vitest": "^4.0.18"
|
|
44
|
+
}
|
|
45
|
+
}
|