@gethmy/agent 1.0.0 → 1.0.1
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 +5 -5
- package/dist/board-helpers.d.ts +23 -0
- package/dist/board-helpers.js +131 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +2 -11761
- package/dist/completion.d.ts +7 -0
- package/dist/completion.js +132 -0
- package/dist/config.d.ts +23 -0
- package/dist/config.js +91 -0
- package/dist/git-pr.d.ts +25 -0
- package/dist/git-pr.js +305 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +165 -11730
- package/dist/log.d.ts +10 -0
- package/dist/log.js +35 -0
- package/dist/merge-monitor.d.ts +23 -0
- package/dist/merge-monitor.js +155 -0
- package/dist/pm.d.ts +14 -0
- package/dist/pm.js +63 -0
- package/dist/pool.d.ts +36 -0
- package/dist/pool.js +134 -0
- package/dist/progress-tracker.d.ts +39 -0
- package/dist/progress-tracker.js +189 -0
- package/dist/prompt.d.ts +5 -0
- package/dist/prompt.js +40 -0
- package/dist/queue.d.ts +37 -0
- package/dist/queue.js +96 -0
- package/dist/reconcile.d.ts +21 -0
- package/dist/reconcile.js +107 -0
- package/dist/review-completion.d.ts +31 -0
- package/dist/review-completion.js +247 -0
- package/dist/review-knowledge.d.ts +14 -0
- package/dist/review-knowledge.js +89 -0
- package/dist/review-prompt.d.ts +12 -0
- package/dist/review-prompt.js +100 -0
- package/dist/review-worker.d.ts +35 -0
- package/dist/review-worker.js +302 -0
- package/dist/review-worktree.d.ts +12 -0
- package/dist/review-worktree.js +83 -0
- package/dist/stream-parser.d.ts +22 -0
- package/dist/stream-parser.js +81 -0
- package/dist/types.d.ts +74 -0
- package/dist/types.js +53 -0
- package/dist/verification.d.ts +16 -0
- package/dist/verification.js +251 -0
- package/dist/watcher.d.ts +21 -0
- package/dist/watcher.js +62 -0
- package/dist/worker.d.ts +34 -0
- package/dist/worker.js +268 -0
- package/dist/worktree.d.ts +13 -0
- package/dist/worktree.js +115 -0
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Push-based agent daemon for [Harmony](https://gethmy.com). Watches board assignm
|
|
|
4
4
|
|
|
5
5
|
## Prerequisites
|
|
6
6
|
|
|
7
|
-
- [Bun](https://bun.sh) >= 1.0.0
|
|
7
|
+
- [Node.js](https://nodejs.org) >= 18 or [Bun](https://bun.sh) >= 1.0.0
|
|
8
8
|
- [Claude CLI](https://docs.anthropic.com/en/docs/claude-code)
|
|
9
9
|
- Git
|
|
10
10
|
- A [Harmony](https://gethmy.com) account with an API key
|
|
@@ -12,11 +12,11 @@ Push-based agent daemon for [Harmony](https://gethmy.com). Watches board assignm
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
# Run directly
|
|
16
|
-
|
|
15
|
+
# Run directly (works with any package manager)
|
|
16
|
+
npx @gethmy/agent
|
|
17
17
|
|
|
18
18
|
# Or install globally
|
|
19
|
-
|
|
19
|
+
npm install -g @gethmy/agent
|
|
20
20
|
harmony-agent
|
|
21
21
|
```
|
|
22
22
|
|
|
@@ -53,7 +53,7 @@ npx @gethmy/mcp setup
|
|
|
53
53
|
Run from your git repository root:
|
|
54
54
|
|
|
55
55
|
```bash
|
|
56
|
-
|
|
56
|
+
npx @gethmy/agent
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
The daemon will:
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { HarmonyApiClient } from "@gethmy/mcp/src/api-client.js";
|
|
2
|
+
import type { Card, Label } from "@harmony/shared";
|
|
3
|
+
/**
|
|
4
|
+
* Check if a card already has the approved label (case-insensitive).
|
|
5
|
+
*/
|
|
6
|
+
export declare function hasApprovedLabel(cardLabels: Label[], approvedLabel: string): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Move a card to a column by name. Fetches the board to resolve column ID.
|
|
9
|
+
*/
|
|
10
|
+
export declare function moveCardToColumn(client: HarmonyApiClient, card: Card, targetColumnName: string): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Find a label by name (case-insensitive) or create it if missing.
|
|
13
|
+
*/
|
|
14
|
+
export declare function findOrCreateLabel(client: HarmonyApiClient, projectId: string, labelName: string, color?: string): Promise<string | null>;
|
|
15
|
+
/**
|
|
16
|
+
* Add a label to a card by name, creating the label if it doesn't exist.
|
|
17
|
+
*/
|
|
18
|
+
export declare function addLabelByName(client: HarmonyApiClient, card: Card, labelName: string, color?: string): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Move a card to a column and add a label in one pass, fetching the board only once.
|
|
21
|
+
* Returns true if the move succeeded, false otherwise.
|
|
22
|
+
*/
|
|
23
|
+
export declare function moveCardAndAddLabel(client: HarmonyApiClient, card: Card, targetColumnName: string, labelName: string, labelColor?: string): Promise<boolean>;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { log } from "./log.js";
|
|
2
|
+
const TAG = "board";
|
|
3
|
+
/**
|
|
4
|
+
* Check if a card already has the approved label (case-insensitive).
|
|
5
|
+
*/
|
|
6
|
+
export function hasApprovedLabel(cardLabels, approvedLabel) {
|
|
7
|
+
return cardLabels.some((l) => l.name.toLowerCase() === approvedLabel.toLowerCase());
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Move a card to a column by name. Fetches the board to resolve column ID.
|
|
11
|
+
*/
|
|
12
|
+
export async function moveCardToColumn(client, card, targetColumnName) {
|
|
13
|
+
try {
|
|
14
|
+
const board = await client.getBoard(card.project_id);
|
|
15
|
+
const targetColumn = board.columns.find((c) => c.name.toLowerCase() === targetColumnName.toLowerCase());
|
|
16
|
+
if (!targetColumn) {
|
|
17
|
+
log.warn(TAG, `Column "${targetColumnName}" not found, skipping move`);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (card.column_id === targetColumn.id) {
|
|
21
|
+
log.debug(TAG, `Card already in "${targetColumnName}"`);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
await client.moveCard(card.id, targetColumn.id);
|
|
25
|
+
log.info(TAG, `Moved #${card.short_id} to "${targetColumnName}"`);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
log.error(TAG, `Failed to move card: ${err instanceof Error ? err.message : err}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Find a label by name (case-insensitive) or create it if missing.
|
|
33
|
+
*/
|
|
34
|
+
export async function findOrCreateLabel(client, projectId, labelName, color = "#22c55e") {
|
|
35
|
+
try {
|
|
36
|
+
const board = await client.getBoard(projectId);
|
|
37
|
+
const labels = board.labels ?? [];
|
|
38
|
+
const existing = labels.find((l) => l.name.toLowerCase() === labelName.toLowerCase());
|
|
39
|
+
if (existing)
|
|
40
|
+
return existing.id;
|
|
41
|
+
const result = await client.createLabel(projectId, {
|
|
42
|
+
name: labelName,
|
|
43
|
+
color,
|
|
44
|
+
});
|
|
45
|
+
const labelId = result?.label?.id;
|
|
46
|
+
if (labelId) {
|
|
47
|
+
log.info(TAG, `Created label "${labelName}"`);
|
|
48
|
+
return labelId;
|
|
49
|
+
}
|
|
50
|
+
log.warn(TAG, `createLabel succeeded but returned no id`);
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
log.error(TAG, `Failed to find/create label "${labelName}": ${err instanceof Error ? err.message : err}`);
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Add a label to a card by name, creating the label if it doesn't exist.
|
|
60
|
+
*/
|
|
61
|
+
export async function addLabelByName(client, card, labelName, color) {
|
|
62
|
+
const labelId = await findOrCreateLabel(client, card.project_id, labelName, color);
|
|
63
|
+
if (!labelId)
|
|
64
|
+
return;
|
|
65
|
+
try {
|
|
66
|
+
await client.addLabelToCard(card.id, labelId);
|
|
67
|
+
log.info(TAG, `Added label "${labelName}" to #${card.short_id}`);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
log.error(TAG, `Failed to add label to card: ${err instanceof Error ? err.message : err}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Move a card to a column and add a label in one pass, fetching the board only once.
|
|
75
|
+
* Returns true if the move succeeded, false otherwise.
|
|
76
|
+
*/
|
|
77
|
+
export async function moveCardAndAddLabel(client, card, targetColumnName, labelName, labelColor = "#8b5cf6") {
|
|
78
|
+
let moved = false;
|
|
79
|
+
try {
|
|
80
|
+
const board = await client.getBoard(card.project_id);
|
|
81
|
+
const columns = board.columns;
|
|
82
|
+
const labels = board.labels ?? [];
|
|
83
|
+
// Move card
|
|
84
|
+
const targetColumn = columns.find((c) => c.name.toLowerCase() === targetColumnName.toLowerCase());
|
|
85
|
+
if (!targetColumn) {
|
|
86
|
+
log.warn(TAG, `Column "${targetColumnName}" not found on board (available: ${columns.map((c) => c.name).join(", ")})`);
|
|
87
|
+
}
|
|
88
|
+
else if (card.column_id === targetColumn.id) {
|
|
89
|
+
log.debug(TAG, `Card #${card.short_id} already in "${targetColumnName}"`);
|
|
90
|
+
moved = true;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
try {
|
|
94
|
+
await client.moveCard(card.id, targetColumn.id);
|
|
95
|
+
log.info(TAG, `Moved #${card.short_id} to "${targetColumnName}"`);
|
|
96
|
+
moved = true;
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
log.error(TAG, `Failed to move #${card.short_id} to "${targetColumnName}": ${err instanceof Error ? err.message : err}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Resolve label ID (find or create)
|
|
103
|
+
let labelId;
|
|
104
|
+
const existing = labels.find((l) => l.name.toLowerCase() === labelName.toLowerCase());
|
|
105
|
+
if (existing) {
|
|
106
|
+
labelId = existing.id;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
const result = await client.createLabel(card.project_id, {
|
|
110
|
+
name: labelName,
|
|
111
|
+
color: labelColor,
|
|
112
|
+
});
|
|
113
|
+
labelId = result?.label?.id;
|
|
114
|
+
if (labelId)
|
|
115
|
+
log.info(TAG, `Created label "${labelName}"`);
|
|
116
|
+
}
|
|
117
|
+
if (labelId) {
|
|
118
|
+
try {
|
|
119
|
+
await client.addLabelToCard(card.id, labelId);
|
|
120
|
+
log.info(TAG, `Added label "${labelName}" to #${card.short_id}`);
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
log.error(TAG, `Failed to add label "${labelName}" to #${card.short_id}: ${err instanceof Error ? err.message : err}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
log.error(TAG, `Failed to prepare move/label for #${card.short_id}: ${err instanceof Error ? err.message : err}`);
|
|
129
|
+
}
|
|
130
|
+
return moved;
|
|
131
|
+
}
|
package/dist/cli.d.ts
ADDED