@gethmy/agent 1.45.0 → 1.46.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 +5 -10
- package/dist/cli.js +160 -23
- package/dist/index.js +142 -19
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -19,10 +19,6 @@ Built for **failsafe auto mode**: crashed daemons recover on restart, misconfigu
|
|
|
19
19
|
npm i -g @gethmy/cli
|
|
20
20
|
hmy agent
|
|
21
21
|
|
|
22
|
-
# Or the daemon package alone
|
|
23
|
-
npm install -g @gethmy/agent
|
|
24
|
-
harmony-agent
|
|
25
|
-
|
|
26
22
|
# Or nothing installed at all (works with any package manager)
|
|
27
23
|
npx @gethmy/agent@latest
|
|
28
24
|
```
|
|
@@ -30,12 +26,11 @@ npx @gethmy/agent@latest
|
|
|
30
26
|
Install when the machine is yours; use `npx` for a container, a CI step or a
|
|
31
27
|
one-off. Both forms stay supported.
|
|
32
28
|
|
|
33
|
-
>
|
|
34
|
-
>
|
|
35
|
-
>
|
|
36
|
-
>
|
|
37
|
-
>
|
|
38
|
-
> `rm -rf ~/.npm/_npx` (or install globally to skip npx caching entirely).
|
|
29
|
+
> **`npx` can serve a stale build.** The npx cache keeps serving the version it
|
|
30
|
+
> first installed, `@latest` included — a restart six minutes after 1.38.0
|
|
31
|
+
> published still ran 1.37.0 — so you get stale startup logs and CLI behavior.
|
|
32
|
+
> If you suspect a stale run, clear the cache with `rm -rf ~/.npm/_npx`, or
|
|
33
|
+
> install `@gethmy/cli` and run `hmy agent` to skip npx caching entirely.
|
|
39
34
|
|
|
40
35
|
## Configuration
|
|
41
36
|
|
package/dist/cli.js
CHANGED
|
@@ -1103,9 +1103,14 @@ var init_commentSerializer = __esm(() => {
|
|
|
1103
1103
|
});
|
|
1104
1104
|
|
|
1105
1105
|
// ../harmony-shared/src/connectCommands.ts
|
|
1106
|
-
|
|
1106
|
+
function hmyConnectCommand(projectSlug) {
|
|
1107
|
+
const slug = projectSlug?.trim();
|
|
1108
|
+
return slug ? `${CONNECT_VERB} ${slug}` : CONNECT_VERB;
|
|
1109
|
+
}
|
|
1110
|
+
var HMY_INSTALL_URL = "https://gethmy.com/install.sh", HMY_INSTALL_COMMAND, HMY_AGENT_COMMAND = "hmy agent", CONNECT_VERB = "hmy connect", HOSTED_MCP_URL = "https://mcp.gethmy.com/mcp", HOSTED_MCP_CONFIG;
|
|
1107
1111
|
var init_connectCommands = __esm(() => {
|
|
1108
1112
|
HMY_INSTALL_COMMAND = `curl -fsSL ${HMY_INSTALL_URL} | bash`;
|
|
1113
|
+
HOSTED_MCP_CONFIG = JSON.stringify({ mcpServers: { harmony: { type: "http", url: HOSTED_MCP_URL } } }, null, 2);
|
|
1109
1114
|
});
|
|
1110
1115
|
|
|
1111
1116
|
// ../harmony-shared/src/constants.ts
|
|
@@ -1578,6 +1583,18 @@ function own(source, key) {
|
|
|
1578
1583
|
return Object.hasOwn(source, key) ? source[key] : undefined;
|
|
1579
1584
|
}
|
|
1580
1585
|
|
|
1586
|
+
// ../harmony-shared/src/packageCommands.ts
|
|
1587
|
+
function npxArgs(pkg, args) {
|
|
1588
|
+
return ["-y", `${SCOPE}/${pkg}@latest`, ...args];
|
|
1589
|
+
}
|
|
1590
|
+
function npxCommand(pkg, args = []) {
|
|
1591
|
+
return ["npx", ...npxArgs(pkg, args)].join(" ");
|
|
1592
|
+
}
|
|
1593
|
+
var SCOPE = "@gethmy", HMY_NPM_INSTALL_COMMAND;
|
|
1594
|
+
var init_packageCommands = __esm(() => {
|
|
1595
|
+
HMY_NPM_INSTALL_COMMAND = `npm i -g ${SCOPE}/cli`;
|
|
1596
|
+
});
|
|
1597
|
+
|
|
1581
1598
|
// ../harmony-shared/src/parsedState.ts
|
|
1582
1599
|
function parseJsonWithoutPrototypes(text) {
|
|
1583
1600
|
return JSON.parse(text, (_key, value) => {
|
|
@@ -2575,6 +2592,7 @@ var init_src = __esm(() => {
|
|
|
2575
2592
|
init_gateEvaluate();
|
|
2576
2593
|
init_logger();
|
|
2577
2594
|
init_memoryQuery();
|
|
2595
|
+
init_packageCommands();
|
|
2578
2596
|
init_playbookAutoBind();
|
|
2579
2597
|
init_playbookCatalog();
|
|
2580
2598
|
init_playbookStage();
|
|
@@ -3516,7 +3534,7 @@ function agentIdentifier(workerId) {
|
|
|
3516
3534
|
function endStatusForCancel(reason) {
|
|
3517
3535
|
return reason === "human_stop" ? "cancelled" : "paused";
|
|
3518
3536
|
}
|
|
3519
|
-
var DEFAULT_FINDING_AUTHORS, DEFAULT_AGENT_CONFIG, IN_PROGRESS_COLUMN = "In Progress", NEED_REVIEW_LABEL = "Need Review", NEED_REVIEW_LABEL_COLOR = "#f59e0b", REVIEW_FAILURE_REASON_MAX = 300, AGENT_NAME = "Harmony Agent", DAEMON_IDENTIFIER_BASE = "harmony-daemon", NOTICE_IDENTIFIER;
|
|
3537
|
+
var DEFAULT_FINDING_AUTHORS, DEFAULT_HUMAN_STAGE_HOLD_MINUTES = 60, DEFAULT_AGENT_CONFIG, IN_PROGRESS_COLUMN = "In Progress", NEED_REVIEW_LABEL = "Need Review", NEED_REVIEW_LABEL_COLOR = "#f59e0b", REVIEW_FAILURE_REASON_MAX = 300, AGENT_NAME = "Harmony Agent", DAEMON_IDENTIFIER_BASE = "harmony-daemon", NOTICE_IDENTIFIER;
|
|
3520
3538
|
var init_types = __esm(() => {
|
|
3521
3539
|
init_src();
|
|
3522
3540
|
init_board_review();
|
|
@@ -3660,7 +3678,12 @@ var init_types = __esm(() => {
|
|
|
3660
3678
|
runLogDays: 30
|
|
3661
3679
|
},
|
|
3662
3680
|
planning: DEFAULT_PLANNING_CONFIG,
|
|
3663
|
-
playbooks: {
|
|
3681
|
+
playbooks: {
|
|
3682
|
+
enabled: true,
|
|
3683
|
+
humanStageColumns: [],
|
|
3684
|
+
humanStageHoldMinutes: DEFAULT_HUMAN_STAGE_HOLD_MINUTES,
|
|
3685
|
+
metrics: {}
|
|
3686
|
+
},
|
|
3664
3687
|
contractFirst: DEFAULT_CONTRACT_CONFIG,
|
|
3665
3688
|
boardReview: DEFAULT_BOARD_REVIEW_CONFIG,
|
|
3666
3689
|
sweep: {
|
|
@@ -4041,13 +4064,13 @@ function loadDaemonConfig() {
|
|
|
4041
4064
|
const projectId = getActiveProjectId(repoRoot);
|
|
4042
4065
|
const userEmail = getUserEmail();
|
|
4043
4066
|
if (!workspaceId) {
|
|
4044
|
-
throw new Error(`No active workspace configured in ${contextSource.path}. Run \`
|
|
4067
|
+
throw new Error(`No active workspace configured in ${contextSource.path}. Run \`${hmyConnectCommand()}\` first (no install: \`${npxCommand("mcp", ["connect"])}\`).`);
|
|
4045
4068
|
}
|
|
4046
4069
|
if (!projectId) {
|
|
4047
|
-
throw new Error(`No active project configured in ${contextSource.path}. Run \`
|
|
4070
|
+
throw new Error(`No active project configured in ${contextSource.path}. Run \`${hmyConnectCommand()}\` first (no install: \`${npxCommand("mcp", ["connect"])}\`).`);
|
|
4048
4071
|
}
|
|
4049
4072
|
if (!userEmail) {
|
|
4050
|
-
throw new Error(`No user email configured in ${contextSource.globalPath}. Run \`
|
|
4073
|
+
throw new Error(`No user email configured in ${contextSource.globalPath}. Run \`${hmyConnectCommand()}\` first (no install: \`${npxCommand("mcp", ["connect"])}\`).`);
|
|
4051
4074
|
}
|
|
4052
4075
|
let agentOverrides = {};
|
|
4053
4076
|
let agentName = "Harmony Agent";
|
|
@@ -4160,6 +4183,7 @@ function createApiClient(config) {
|
|
|
4160
4183
|
}
|
|
4161
4184
|
var TAG5 = "config", NOT_A_REPOSITORY_EXIT = 128, warnedLegacyConfigDir = false;
|
|
4162
4185
|
var init_config = __esm(() => {
|
|
4186
|
+
init_src();
|
|
4163
4187
|
init_config_merge();
|
|
4164
4188
|
init_config_validation();
|
|
4165
4189
|
init_paths();
|
|
@@ -8817,7 +8841,7 @@ class StateStore {
|
|
|
8817
8841
|
const rec = this.getCard(cardId);
|
|
8818
8842
|
if (!rec)
|
|
8819
8843
|
return;
|
|
8820
|
-
if (rec.attempts === 0 && !rec.ciRepairAttempts && rec.ciRepairParkedAt == null && (!clearTurns || !rec.totalTurns && !rec.runStarts)) {
|
|
8844
|
+
if (rec.attempts === 0 && !rec.ciRepairAttempts && rec.ciRepairParkedAt == null && rec.stageHold == null && (!clearTurns || !rec.totalTurns && !rec.runStarts)) {
|
|
8821
8845
|
return;
|
|
8822
8846
|
}
|
|
8823
8847
|
rec.attempts = 0;
|
|
@@ -8827,6 +8851,7 @@ class StateStore {
|
|
|
8827
8851
|
rec.totalTurns = 0;
|
|
8828
8852
|
if (clearTurns)
|
|
8829
8853
|
rec.runStarts = 0;
|
|
8854
|
+
rec.stageHold = null;
|
|
8830
8855
|
await this.persist();
|
|
8831
8856
|
}
|
|
8832
8857
|
getCiRepairAttempts(cardId) {
|
|
@@ -8909,6 +8934,29 @@ class StateStore {
|
|
|
8909
8934
|
getCardRunStarts(cardId) {
|
|
8910
8935
|
return this.getCard(cardId)?.runStarts ?? 0;
|
|
8911
8936
|
}
|
|
8937
|
+
getStageHold(cardId) {
|
|
8938
|
+
return this.getCard(cardId)?.stageHold ?? null;
|
|
8939
|
+
}
|
|
8940
|
+
async recordStageHold(cardId, hold) {
|
|
8941
|
+
const rec = this.ensureCard(cardId);
|
|
8942
|
+
const prior = rec.stageHold ?? null;
|
|
8943
|
+
const announced = prior != null && prior.stageId === hold.stageId && prior.reason === hold.reason;
|
|
8944
|
+
rec.stageHold = cloneWithoutPrototype({
|
|
8945
|
+
stageId: hold.stageId,
|
|
8946
|
+
reason: hold.reason,
|
|
8947
|
+
until: hold.untilMs,
|
|
8948
|
+
announcedAt: announced ? prior.announcedAt : Date.now()
|
|
8949
|
+
});
|
|
8950
|
+
await this.persist();
|
|
8951
|
+
return { announced };
|
|
8952
|
+
}
|
|
8953
|
+
async clearStageHold(cardId) {
|
|
8954
|
+
const rec = this.getCard(cardId);
|
|
8955
|
+
if (!rec || rec.stageHold == null)
|
|
8956
|
+
return;
|
|
8957
|
+
rec.stageHold = null;
|
|
8958
|
+
await this.persist();
|
|
8959
|
+
}
|
|
8912
8960
|
getCardCostCents(cardId) {
|
|
8913
8961
|
return this.getCard(cardId)?.totalCostCents ?? 0;
|
|
8914
8962
|
}
|
|
@@ -10219,6 +10267,27 @@ class SleepGuard {
|
|
|
10219
10267
|
var TAG26 = "sleep-guard";
|
|
10220
10268
|
var init_sleep_guard = () => {};
|
|
10221
10269
|
|
|
10270
|
+
// src/stage-hold.ts
|
|
10271
|
+
function classifyStageHold(card, hold, nowMs) {
|
|
10272
|
+
if (!hold)
|
|
10273
|
+
return { kind: "none" };
|
|
10274
|
+
if (!card.current_stage || card.current_stage !== hold.stageId) {
|
|
10275
|
+
return { kind: "stale" };
|
|
10276
|
+
}
|
|
10277
|
+
if (nowMs >= hold.until)
|
|
10278
|
+
return { kind: "lapsed" };
|
|
10279
|
+
const remainingMin = Math.ceil((hold.until - nowMs) / 60000);
|
|
10280
|
+
return {
|
|
10281
|
+
kind: "holding",
|
|
10282
|
+
detail: `parked on human-owned stage "${hold.stageId}" — holding for ~${remainingMin}m`
|
|
10283
|
+
};
|
|
10284
|
+
}
|
|
10285
|
+
function stageHoldUntil(holdMinutes, nowMs) {
|
|
10286
|
+
if (!Number.isFinite(holdMinutes) || holdMinutes <= 0)
|
|
10287
|
+
return nowMs;
|
|
10288
|
+
return nowMs + holdMinutes * 60000;
|
|
10289
|
+
}
|
|
10290
|
+
|
|
10222
10291
|
// src/unblock.ts
|
|
10223
10292
|
import { log as log30 } from "@gethmy/harness";
|
|
10224
10293
|
async function fetchBlocksLinks(client, cardId) {
|
|
@@ -11455,6 +11524,29 @@ var init_stage_advance = __esm(() => {
|
|
|
11455
11524
|
});
|
|
11456
11525
|
|
|
11457
11526
|
// src/workspace-model-config.ts
|
|
11527
|
+
function layerPlatformDefaults(platform, ws) {
|
|
11528
|
+
if (!platform)
|
|
11529
|
+
return ws ?? null;
|
|
11530
|
+
if (!ws)
|
|
11531
|
+
return platform;
|
|
11532
|
+
const merged = { ...platform };
|
|
11533
|
+
for (const [key, value] of Object.entries(ws)) {
|
|
11534
|
+
if (value !== null && value !== undefined) {
|
|
11535
|
+
merged[key] = value;
|
|
11536
|
+
}
|
|
11537
|
+
}
|
|
11538
|
+
if (platform.tiers || ws.tiers) {
|
|
11539
|
+
const tiers = {};
|
|
11540
|
+
for (const layer of [platform.tiers, ws.tiers]) {
|
|
11541
|
+
for (const [tier, model] of Object.entries(layer ?? {})) {
|
|
11542
|
+
if (model)
|
|
11543
|
+
tiers[tier] = model;
|
|
11544
|
+
}
|
|
11545
|
+
}
|
|
11546
|
+
merged.tiers = tiers;
|
|
11547
|
+
}
|
|
11548
|
+
return merged;
|
|
11549
|
+
}
|
|
11458
11550
|
function workspaceConfigToPartial(ws) {
|
|
11459
11551
|
const claude = {};
|
|
11460
11552
|
if (ws.implement_model)
|
|
@@ -11977,7 +12069,7 @@ class Worker {
|
|
|
11977
12069
|
stageCtx = await this.resolveStageContext(card);
|
|
11978
12070
|
if (stageCtx.kind === "hold") {
|
|
11979
12071
|
this.held = true;
|
|
11980
|
-
await this.holdStageCard(card, stageCtx.reason, stageCtx.wait);
|
|
12072
|
+
await this.holdStageCard(card, stageCtx.reason, stageCtx.wait, stageCtx.wait);
|
|
11981
12073
|
return;
|
|
11982
12074
|
}
|
|
11983
12075
|
if (stageCtx.kind === "fanout") {
|
|
@@ -12535,15 +12627,35 @@ class Worker {
|
|
|
12535
12627
|
}
|
|
12536
12628
|
}
|
|
12537
12629
|
}
|
|
12538
|
-
async holdStageCard(card, reason, wait = false) {
|
|
12630
|
+
async holdStageCard(card, reason, wait = false, armCooldown = false) {
|
|
12539
12631
|
log34.info(this.tag, `Holding #${card.short_id}: ${reason}`);
|
|
12540
12632
|
await this.stateStore.decrementAttempt(card.id);
|
|
12541
|
-
|
|
12542
|
-
|
|
12543
|
-
|
|
12544
|
-
|
|
12545
|
-
|
|
12546
|
-
|
|
12633
|
+
let announced = false;
|
|
12634
|
+
const holdStage = armCooldown ? card.current_stage : null;
|
|
12635
|
+
if (holdStage) {
|
|
12636
|
+
try {
|
|
12637
|
+
const recorded = await this.stateStore.recordStageHold(card.id, {
|
|
12638
|
+
stageId: holdStage,
|
|
12639
|
+
reason,
|
|
12640
|
+
untilMs: stageHoldUntil(this.config.playbooks.humanStageHoldMinutes ?? DEFAULT_HUMAN_STAGE_HOLD_MINUTES, Date.now())
|
|
12641
|
+
});
|
|
12642
|
+
announced = recorded.announced;
|
|
12643
|
+
} catch (err) {
|
|
12644
|
+
log34.warn(this.tag, `stage hold not recorded on #${card.short_id}: ${err instanceof Error ? err.message : err}`);
|
|
12645
|
+
}
|
|
12646
|
+
}
|
|
12647
|
+
if (announced) {
|
|
12648
|
+
log34.debug(this.tag, `#${card.short_id} already carries this blocker — not reposting`);
|
|
12649
|
+
} else {
|
|
12650
|
+
try {
|
|
12651
|
+
await this.client.addComment(card.id, reason, {
|
|
12652
|
+
commentType: "blocker",
|
|
12653
|
+
agentSessionId: this.sessionId ?? undefined
|
|
12654
|
+
});
|
|
12655
|
+
} catch {
|
|
12656
|
+
await this.stateStore.clearStageHold(card.id).catch(() => {});
|
|
12657
|
+
}
|
|
12658
|
+
}
|
|
12547
12659
|
try {
|
|
12548
12660
|
await runTransition(this.client, card, {
|
|
12549
12661
|
removeLabels: ["agent"],
|
|
@@ -13970,8 +14082,8 @@ class Pool {
|
|
|
13970
14082
|
this.reviewQueue = new PriorityQueue(config);
|
|
13971
14083
|
this.budget = new BudgetGuard(config.budget, this.stateStore);
|
|
13972
14084
|
const workspaceModels = daemonConfig ? new WorkspaceModelCache(async () => {
|
|
13973
|
-
const { config: wsConfig } = await client.getWorkspaceModelConfig(workspaceId);
|
|
13974
|
-
return wsConfig
|
|
14085
|
+
const { config: wsConfig, platformDefaults } = await client.getWorkspaceModelConfig(workspaceId);
|
|
14086
|
+
return layerPlatformDefaults(platformDefaults, wsConfig);
|
|
13975
14087
|
}) : undefined;
|
|
13976
14088
|
const modelCatalog = daemonConfig ? new WorkspaceModelCache(async () => {
|
|
13977
14089
|
const { models } = await client.getModelCatalog();
|
|
@@ -14038,6 +14150,14 @@ class Pool {
|
|
|
14038
14150
|
await this.emitWaiting(card.id, `Paused — Anthropic API limit, retrying in ~${Math.round(cooldownMs / 1000)}s`);
|
|
14039
14151
|
return;
|
|
14040
14152
|
}
|
|
14153
|
+
const stageHold = classifyStageHold(card, this.stateStore.getStageHold(card.id), Date.now());
|
|
14154
|
+
if (stageHold.kind === "holding") {
|
|
14155
|
+
log36.debug(TAG32, `#${card.short_id} held — ${stageHold.detail}`);
|
|
14156
|
+
return;
|
|
14157
|
+
}
|
|
14158
|
+
if (stageHold.kind === "stale") {
|
|
14159
|
+
await this.stateStore.clearStageHold(card.id);
|
|
14160
|
+
}
|
|
14041
14161
|
const decision = this.budget.check(card.id);
|
|
14042
14162
|
if (!decision.allow) {
|
|
14043
14163
|
if (decision.reason === "daily_budget") {
|
|
@@ -14736,6 +14856,7 @@ var init_pool = __esm(() => {
|
|
|
14736
14856
|
init_unblock();
|
|
14737
14857
|
init_worker();
|
|
14738
14858
|
init_workspace_model_cache();
|
|
14859
|
+
init_workspace_model_config();
|
|
14739
14860
|
});
|
|
14740
14861
|
|
|
14741
14862
|
// src/port-registry.ts
|
|
@@ -14974,6 +15095,8 @@ var init_repo_dirs = __esm(() => {
|
|
|
14974
15095
|
|
|
14975
15096
|
// src/card-trust.ts
|
|
14976
15097
|
function isTrustedCardAuthor(card, trustedAuthors) {
|
|
15098
|
+
if (card.source != null)
|
|
15099
|
+
return false;
|
|
14977
15100
|
return card.created_by != null && trustedAuthors.has(card.created_by);
|
|
14978
15101
|
}
|
|
14979
15102
|
|
|
@@ -15033,7 +15156,7 @@ async function reclaimPreReviewStrands(opts) {
|
|
|
15033
15156
|
continue;
|
|
15034
15157
|
const daemonBranch = daemonBranches.get(card.id);
|
|
15035
15158
|
if (!isTrustedCardAuthor(card, trustedAuthors) && daemonBranch !== branch) {
|
|
15036
|
-
log40.debug(TAG36, `#${card.short_id} - skipped: author ${card.created_by ?? "(none)"} is not trusted, and ${daemonBranch ? `the card records ${branch} while this daemon pushed ${daemonBranch}` : "this daemon has pushed no branch for it"}`);
|
|
15159
|
+
log40.debug(TAG36, `#${card.short_id} - skipped: ${card.source != null ? `card was filed externally (source: ${card.source})` : `author ${card.created_by ?? "(none)"} is not trusted`}, and ${daemonBranch ? `the card records ${branch} while this daemon pushed ${daemonBranch}` : "this daemon has pushed no branch for it"}`);
|
|
15037
15160
|
continue;
|
|
15038
15161
|
}
|
|
15039
15162
|
const labels = resolveCardLabels(card, labelMap);
|
|
@@ -15271,7 +15394,7 @@ function rankSweepCandidates(opts) {
|
|
|
15271
15394
|
continue;
|
|
15272
15395
|
}
|
|
15273
15396
|
if (!isTrustedCardAuthor(card, trustedAuthors)) {
|
|
15274
|
-
skip2(card, "untrusted_author", card.created_by == null ? "card has no recorded author" : `author ${card.created_by} is not in sweep.trustedAuthors`);
|
|
15397
|
+
skip2(card, "untrusted_author", card.source != null ? `card was filed externally (source: ${card.source})` : card.created_by == null ? "card has no recorded author" : `author ${card.created_by} is not in sweep.trustedAuthors`);
|
|
15275
15398
|
continue;
|
|
15276
15399
|
}
|
|
15277
15400
|
if (card.assigned_agent_id != null) {
|
|
@@ -18082,7 +18205,7 @@ var init_head_anchor = () => {};
|
|
|
18082
18205
|
|
|
18083
18206
|
// src/merge-cleanup.ts
|
|
18084
18207
|
import { execFileSync as execFileSync11 } from "node:child_process";
|
|
18085
|
-
import { existsSync as existsSync7, realpathSync as realpathSync2, statSync as statSync6 } from "node:fs";
|
|
18208
|
+
import { existsSync as existsSync7, lstatSync as lstatSync3, realpathSync as realpathSync2, statSync as statSync6 } from "node:fs";
|
|
18086
18209
|
import { basename, dirname as dirname7, isAbsolute, resolve as resolve6, sep as sep4 } from "node:path";
|
|
18087
18210
|
import { cleanupWorktree as cleanupWorktree6, GIT_NO_HOOKS as GIT_NO_HOOKS12, log as log52 } from "@gethmy/harness";
|
|
18088
18211
|
function canonicalize(p) {
|
|
@@ -18187,8 +18310,20 @@ function classifyWorktreeRegistration(worktreePath, cwd) {
|
|
|
18187
18310
|
function isRegisteredWorktree(worktreePath, cwd) {
|
|
18188
18311
|
return classifyWorktreeRegistration(worktreePath, cwd).kind === "registered";
|
|
18189
18312
|
}
|
|
18313
|
+
function pathAbsent(p) {
|
|
18314
|
+
try {
|
|
18315
|
+
lstatSync3(p);
|
|
18316
|
+
return false;
|
|
18317
|
+
} catch {
|
|
18318
|
+
return true;
|
|
18319
|
+
}
|
|
18320
|
+
}
|
|
18190
18321
|
function cleanupMergedWorktree(args) {
|
|
18191
|
-
|
|
18322
|
+
const registration = classifyWorktreeRegistration(args.worktreePath, args.cwd);
|
|
18323
|
+
if (registration.kind === "unregistered" && pathAbsent(args.worktreePath)) {
|
|
18324
|
+
return { removed: true, alreadyGone: true };
|
|
18325
|
+
}
|
|
18326
|
+
if (registration.kind !== "registered") {
|
|
18192
18327
|
const reason = `refusing to clean up ${args.worktreePath} — git does not list it as a ` + `worktree of the repository at ${args.cwd}, and removing a path git ` + `does not manage would be a recursive delete of an unknown directory. ` + `Pass the worktree path Step B5 created, and re-run from the ` + `repository root.`;
|
|
18193
18328
|
log52.warn(TAG48, reason);
|
|
18194
18329
|
return { removed: false, reason };
|
|
@@ -18461,7 +18596,8 @@ async function finish(deps) {
|
|
|
18461
18596
|
deps.emit({
|
|
18462
18597
|
type: "cleaned",
|
|
18463
18598
|
worktree: worktreePath,
|
|
18464
|
-
branch: branchGone ? branch : null
|
|
18599
|
+
branch: branchGone ? branch : null,
|
|
18600
|
+
...out.alreadyGone ? { alreadyRemoved: true } : {}
|
|
18465
18601
|
});
|
|
18466
18602
|
}
|
|
18467
18603
|
} catch (err) {
|
|
@@ -18632,6 +18768,7 @@ var init_scan_commands = __esm(() => {
|
|
|
18632
18768
|
});
|
|
18633
18769
|
|
|
18634
18770
|
// src/cli.ts
|
|
18771
|
+
init_src();
|
|
18635
18772
|
init_package_version();
|
|
18636
18773
|
import { readFileSync as readFileSync11, realpathSync as realpathSync4 } from "node:fs";
|
|
18637
18774
|
import { dirname as dirname8, join as join10 } from "node:path";
|
|
@@ -18911,7 +19048,7 @@ async function reportBuildFreshness(version) {
|
|
|
18911
19048
|
}
|
|
18912
19049
|
if (published === version)
|
|
18913
19050
|
return;
|
|
18914
|
-
process.stderr.write(`preflight: npm serves ${published}. If that is NEWER than the build above, this one is stale — ` +
|
|
19051
|
+
process.stderr.write(`preflight: npm serves ${published}. If that is NEWER than the build above, this one is stale — ` + `\`${HMY_NPM_INSTALL_COMMAND}\` and run it as \`${HMY_AGENT_COMMAND}\`, or clear the npx cache (\`rm -rf ~/.npm/_npx\`), because \`@latest\` alone does not re-resolve it.
|
|
18915
19052
|
`);
|
|
18916
19053
|
}
|
|
18917
19054
|
async function doctorCommand() {
|
package/dist/index.js
CHANGED
|
@@ -1102,9 +1102,14 @@ var init_commentSerializer = __esm(() => {
|
|
|
1102
1102
|
});
|
|
1103
1103
|
|
|
1104
1104
|
// ../harmony-shared/src/connectCommands.ts
|
|
1105
|
-
|
|
1105
|
+
function hmyConnectCommand(projectSlug) {
|
|
1106
|
+
const slug = projectSlug?.trim();
|
|
1107
|
+
return slug ? `${CONNECT_VERB} ${slug}` : CONNECT_VERB;
|
|
1108
|
+
}
|
|
1109
|
+
var HMY_INSTALL_URL = "https://gethmy.com/install.sh", HMY_INSTALL_COMMAND, HMY_AGENT_COMMAND = "hmy agent", CONNECT_VERB = "hmy connect", HOSTED_MCP_URL = "https://mcp.gethmy.com/mcp", HOSTED_MCP_CONFIG;
|
|
1106
1110
|
var init_connectCommands = __esm(() => {
|
|
1107
1111
|
HMY_INSTALL_COMMAND = `curl -fsSL ${HMY_INSTALL_URL} | bash`;
|
|
1112
|
+
HOSTED_MCP_CONFIG = JSON.stringify({ mcpServers: { harmony: { type: "http", url: HOSTED_MCP_URL } } }, null, 2);
|
|
1108
1113
|
});
|
|
1109
1114
|
|
|
1110
1115
|
// ../harmony-shared/src/constants.ts
|
|
@@ -1577,6 +1582,18 @@ function own(source, key) {
|
|
|
1577
1582
|
return Object.hasOwn(source, key) ? source[key] : undefined;
|
|
1578
1583
|
}
|
|
1579
1584
|
|
|
1585
|
+
// ../harmony-shared/src/packageCommands.ts
|
|
1586
|
+
function npxArgs(pkg, args) {
|
|
1587
|
+
return ["-y", `${SCOPE}/${pkg}@latest`, ...args];
|
|
1588
|
+
}
|
|
1589
|
+
function npxCommand(pkg, args = []) {
|
|
1590
|
+
return ["npx", ...npxArgs(pkg, args)].join(" ");
|
|
1591
|
+
}
|
|
1592
|
+
var SCOPE = "@gethmy", HMY_NPM_INSTALL_COMMAND;
|
|
1593
|
+
var init_packageCommands = __esm(() => {
|
|
1594
|
+
HMY_NPM_INSTALL_COMMAND = `npm i -g ${SCOPE}/cli`;
|
|
1595
|
+
});
|
|
1596
|
+
|
|
1580
1597
|
// ../harmony-shared/src/parsedState.ts
|
|
1581
1598
|
function parseJsonWithoutPrototypes(text) {
|
|
1582
1599
|
return JSON.parse(text, (_key, value) => {
|
|
@@ -2574,6 +2591,7 @@ var init_src = __esm(() => {
|
|
|
2574
2591
|
init_gateEvaluate();
|
|
2575
2592
|
init_logger();
|
|
2576
2593
|
init_memoryQuery();
|
|
2594
|
+
init_packageCommands();
|
|
2577
2595
|
init_playbookAutoBind();
|
|
2578
2596
|
init_playbookCatalog();
|
|
2579
2597
|
init_playbookStage();
|
|
@@ -3515,7 +3533,7 @@ function agentIdentifier(workerId) {
|
|
|
3515
3533
|
function endStatusForCancel(reason) {
|
|
3516
3534
|
return reason === "human_stop" ? "cancelled" : "paused";
|
|
3517
3535
|
}
|
|
3518
|
-
var DEFAULT_FINDING_AUTHORS, DEFAULT_AGENT_CONFIG, IN_PROGRESS_COLUMN = "In Progress", NEED_REVIEW_LABEL = "Need Review", NEED_REVIEW_LABEL_COLOR = "#f59e0b", REVIEW_FAILURE_REASON_MAX = 300, AGENT_NAME = "Harmony Agent", DAEMON_IDENTIFIER_BASE = "harmony-daemon", NOTICE_IDENTIFIER;
|
|
3536
|
+
var DEFAULT_FINDING_AUTHORS, DEFAULT_HUMAN_STAGE_HOLD_MINUTES = 60, DEFAULT_AGENT_CONFIG, IN_PROGRESS_COLUMN = "In Progress", NEED_REVIEW_LABEL = "Need Review", NEED_REVIEW_LABEL_COLOR = "#f59e0b", REVIEW_FAILURE_REASON_MAX = 300, AGENT_NAME = "Harmony Agent", DAEMON_IDENTIFIER_BASE = "harmony-daemon", NOTICE_IDENTIFIER;
|
|
3519
3537
|
var init_types = __esm(() => {
|
|
3520
3538
|
init_src();
|
|
3521
3539
|
init_board_review();
|
|
@@ -3659,7 +3677,12 @@ var init_types = __esm(() => {
|
|
|
3659
3677
|
runLogDays: 30
|
|
3660
3678
|
},
|
|
3661
3679
|
planning: DEFAULT_PLANNING_CONFIG,
|
|
3662
|
-
playbooks: {
|
|
3680
|
+
playbooks: {
|
|
3681
|
+
enabled: true,
|
|
3682
|
+
humanStageColumns: [],
|
|
3683
|
+
humanStageHoldMinutes: DEFAULT_HUMAN_STAGE_HOLD_MINUTES,
|
|
3684
|
+
metrics: {}
|
|
3685
|
+
},
|
|
3663
3686
|
contractFirst: DEFAULT_CONTRACT_CONFIG,
|
|
3664
3687
|
boardReview: DEFAULT_BOARD_REVIEW_CONFIG,
|
|
3665
3688
|
sweep: {
|
|
@@ -4040,13 +4063,13 @@ function loadDaemonConfig() {
|
|
|
4040
4063
|
const projectId = getActiveProjectId(repoRoot);
|
|
4041
4064
|
const userEmail = getUserEmail();
|
|
4042
4065
|
if (!workspaceId) {
|
|
4043
|
-
throw new Error(`No active workspace configured in ${contextSource.path}. Run \`
|
|
4066
|
+
throw new Error(`No active workspace configured in ${contextSource.path}. Run \`${hmyConnectCommand()}\` first (no install: \`${npxCommand("mcp", ["connect"])}\`).`);
|
|
4044
4067
|
}
|
|
4045
4068
|
if (!projectId) {
|
|
4046
|
-
throw new Error(`No active project configured in ${contextSource.path}. Run \`
|
|
4069
|
+
throw new Error(`No active project configured in ${contextSource.path}. Run \`${hmyConnectCommand()}\` first (no install: \`${npxCommand("mcp", ["connect"])}\`).`);
|
|
4047
4070
|
}
|
|
4048
4071
|
if (!userEmail) {
|
|
4049
|
-
throw new Error(`No user email configured in ${contextSource.globalPath}. Run \`
|
|
4072
|
+
throw new Error(`No user email configured in ${contextSource.globalPath}. Run \`${hmyConnectCommand()}\` first (no install: \`${npxCommand("mcp", ["connect"])}\`).`);
|
|
4050
4073
|
}
|
|
4051
4074
|
let agentOverrides = {};
|
|
4052
4075
|
let agentName = "Harmony Agent";
|
|
@@ -4159,6 +4182,7 @@ function createApiClient(config) {
|
|
|
4159
4182
|
}
|
|
4160
4183
|
var TAG5 = "config", NOT_A_REPOSITORY_EXIT = 128, warnedLegacyConfigDir = false;
|
|
4161
4184
|
var init_config = __esm(() => {
|
|
4185
|
+
init_src();
|
|
4162
4186
|
init_config_merge();
|
|
4163
4187
|
init_config_validation();
|
|
4164
4188
|
init_paths();
|
|
@@ -8816,7 +8840,7 @@ class StateStore {
|
|
|
8816
8840
|
const rec = this.getCard(cardId);
|
|
8817
8841
|
if (!rec)
|
|
8818
8842
|
return;
|
|
8819
|
-
if (rec.attempts === 0 && !rec.ciRepairAttempts && rec.ciRepairParkedAt == null && (!clearTurns || !rec.totalTurns && !rec.runStarts)) {
|
|
8843
|
+
if (rec.attempts === 0 && !rec.ciRepairAttempts && rec.ciRepairParkedAt == null && rec.stageHold == null && (!clearTurns || !rec.totalTurns && !rec.runStarts)) {
|
|
8820
8844
|
return;
|
|
8821
8845
|
}
|
|
8822
8846
|
rec.attempts = 0;
|
|
@@ -8826,6 +8850,7 @@ class StateStore {
|
|
|
8826
8850
|
rec.totalTurns = 0;
|
|
8827
8851
|
if (clearTurns)
|
|
8828
8852
|
rec.runStarts = 0;
|
|
8853
|
+
rec.stageHold = null;
|
|
8829
8854
|
await this.persist();
|
|
8830
8855
|
}
|
|
8831
8856
|
getCiRepairAttempts(cardId) {
|
|
@@ -8908,6 +8933,29 @@ class StateStore {
|
|
|
8908
8933
|
getCardRunStarts(cardId) {
|
|
8909
8934
|
return this.getCard(cardId)?.runStarts ?? 0;
|
|
8910
8935
|
}
|
|
8936
|
+
getStageHold(cardId) {
|
|
8937
|
+
return this.getCard(cardId)?.stageHold ?? null;
|
|
8938
|
+
}
|
|
8939
|
+
async recordStageHold(cardId, hold) {
|
|
8940
|
+
const rec = this.ensureCard(cardId);
|
|
8941
|
+
const prior = rec.stageHold ?? null;
|
|
8942
|
+
const announced = prior != null && prior.stageId === hold.stageId && prior.reason === hold.reason;
|
|
8943
|
+
rec.stageHold = cloneWithoutPrototype({
|
|
8944
|
+
stageId: hold.stageId,
|
|
8945
|
+
reason: hold.reason,
|
|
8946
|
+
until: hold.untilMs,
|
|
8947
|
+
announcedAt: announced ? prior.announcedAt : Date.now()
|
|
8948
|
+
});
|
|
8949
|
+
await this.persist();
|
|
8950
|
+
return { announced };
|
|
8951
|
+
}
|
|
8952
|
+
async clearStageHold(cardId) {
|
|
8953
|
+
const rec = this.getCard(cardId);
|
|
8954
|
+
if (!rec || rec.stageHold == null)
|
|
8955
|
+
return;
|
|
8956
|
+
rec.stageHold = null;
|
|
8957
|
+
await this.persist();
|
|
8958
|
+
}
|
|
8911
8959
|
getCardCostCents(cardId) {
|
|
8912
8960
|
return this.getCard(cardId)?.totalCostCents ?? 0;
|
|
8913
8961
|
}
|
|
@@ -10218,6 +10266,27 @@ class SleepGuard {
|
|
|
10218
10266
|
var TAG26 = "sleep-guard";
|
|
10219
10267
|
var init_sleep_guard = () => {};
|
|
10220
10268
|
|
|
10269
|
+
// src/stage-hold.ts
|
|
10270
|
+
function classifyStageHold(card, hold, nowMs) {
|
|
10271
|
+
if (!hold)
|
|
10272
|
+
return { kind: "none" };
|
|
10273
|
+
if (!card.current_stage || card.current_stage !== hold.stageId) {
|
|
10274
|
+
return { kind: "stale" };
|
|
10275
|
+
}
|
|
10276
|
+
if (nowMs >= hold.until)
|
|
10277
|
+
return { kind: "lapsed" };
|
|
10278
|
+
const remainingMin = Math.ceil((hold.until - nowMs) / 60000);
|
|
10279
|
+
return {
|
|
10280
|
+
kind: "holding",
|
|
10281
|
+
detail: `parked on human-owned stage "${hold.stageId}" — holding for ~${remainingMin}m`
|
|
10282
|
+
};
|
|
10283
|
+
}
|
|
10284
|
+
function stageHoldUntil(holdMinutes, nowMs) {
|
|
10285
|
+
if (!Number.isFinite(holdMinutes) || holdMinutes <= 0)
|
|
10286
|
+
return nowMs;
|
|
10287
|
+
return nowMs + holdMinutes * 60000;
|
|
10288
|
+
}
|
|
10289
|
+
|
|
10221
10290
|
// src/unblock.ts
|
|
10222
10291
|
import { log as log30 } from "@gethmy/harness";
|
|
10223
10292
|
async function fetchBlocksLinks(client, cardId) {
|
|
@@ -11454,6 +11523,29 @@ var init_stage_advance = __esm(() => {
|
|
|
11454
11523
|
});
|
|
11455
11524
|
|
|
11456
11525
|
// src/workspace-model-config.ts
|
|
11526
|
+
function layerPlatformDefaults(platform, ws) {
|
|
11527
|
+
if (!platform)
|
|
11528
|
+
return ws ?? null;
|
|
11529
|
+
if (!ws)
|
|
11530
|
+
return platform;
|
|
11531
|
+
const merged = { ...platform };
|
|
11532
|
+
for (const [key, value] of Object.entries(ws)) {
|
|
11533
|
+
if (value !== null && value !== undefined) {
|
|
11534
|
+
merged[key] = value;
|
|
11535
|
+
}
|
|
11536
|
+
}
|
|
11537
|
+
if (platform.tiers || ws.tiers) {
|
|
11538
|
+
const tiers = {};
|
|
11539
|
+
for (const layer of [platform.tiers, ws.tiers]) {
|
|
11540
|
+
for (const [tier, model] of Object.entries(layer ?? {})) {
|
|
11541
|
+
if (model)
|
|
11542
|
+
tiers[tier] = model;
|
|
11543
|
+
}
|
|
11544
|
+
}
|
|
11545
|
+
merged.tiers = tiers;
|
|
11546
|
+
}
|
|
11547
|
+
return merged;
|
|
11548
|
+
}
|
|
11457
11549
|
function workspaceConfigToPartial(ws) {
|
|
11458
11550
|
const claude = {};
|
|
11459
11551
|
if (ws.implement_model)
|
|
@@ -11976,7 +12068,7 @@ class Worker {
|
|
|
11976
12068
|
stageCtx = await this.resolveStageContext(card);
|
|
11977
12069
|
if (stageCtx.kind === "hold") {
|
|
11978
12070
|
this.held = true;
|
|
11979
|
-
await this.holdStageCard(card, stageCtx.reason, stageCtx.wait);
|
|
12071
|
+
await this.holdStageCard(card, stageCtx.reason, stageCtx.wait, stageCtx.wait);
|
|
11980
12072
|
return;
|
|
11981
12073
|
}
|
|
11982
12074
|
if (stageCtx.kind === "fanout") {
|
|
@@ -12534,15 +12626,35 @@ class Worker {
|
|
|
12534
12626
|
}
|
|
12535
12627
|
}
|
|
12536
12628
|
}
|
|
12537
|
-
async holdStageCard(card, reason, wait = false) {
|
|
12629
|
+
async holdStageCard(card, reason, wait = false, armCooldown = false) {
|
|
12538
12630
|
log34.info(this.tag, `Holding #${card.short_id}: ${reason}`);
|
|
12539
12631
|
await this.stateStore.decrementAttempt(card.id);
|
|
12540
|
-
|
|
12541
|
-
|
|
12542
|
-
|
|
12543
|
-
|
|
12544
|
-
|
|
12545
|
-
|
|
12632
|
+
let announced = false;
|
|
12633
|
+
const holdStage = armCooldown ? card.current_stage : null;
|
|
12634
|
+
if (holdStage) {
|
|
12635
|
+
try {
|
|
12636
|
+
const recorded = await this.stateStore.recordStageHold(card.id, {
|
|
12637
|
+
stageId: holdStage,
|
|
12638
|
+
reason,
|
|
12639
|
+
untilMs: stageHoldUntil(this.config.playbooks.humanStageHoldMinutes ?? DEFAULT_HUMAN_STAGE_HOLD_MINUTES, Date.now())
|
|
12640
|
+
});
|
|
12641
|
+
announced = recorded.announced;
|
|
12642
|
+
} catch (err) {
|
|
12643
|
+
log34.warn(this.tag, `stage hold not recorded on #${card.short_id}: ${err instanceof Error ? err.message : err}`);
|
|
12644
|
+
}
|
|
12645
|
+
}
|
|
12646
|
+
if (announced) {
|
|
12647
|
+
log34.debug(this.tag, `#${card.short_id} already carries this blocker — not reposting`);
|
|
12648
|
+
} else {
|
|
12649
|
+
try {
|
|
12650
|
+
await this.client.addComment(card.id, reason, {
|
|
12651
|
+
commentType: "blocker",
|
|
12652
|
+
agentSessionId: this.sessionId ?? undefined
|
|
12653
|
+
});
|
|
12654
|
+
} catch {
|
|
12655
|
+
await this.stateStore.clearStageHold(card.id).catch(() => {});
|
|
12656
|
+
}
|
|
12657
|
+
}
|
|
12546
12658
|
try {
|
|
12547
12659
|
await runTransition(this.client, card, {
|
|
12548
12660
|
removeLabels: ["agent"],
|
|
@@ -13969,8 +14081,8 @@ class Pool {
|
|
|
13969
14081
|
this.reviewQueue = new PriorityQueue(config);
|
|
13970
14082
|
this.budget = new BudgetGuard(config.budget, this.stateStore);
|
|
13971
14083
|
const workspaceModels = daemonConfig ? new WorkspaceModelCache(async () => {
|
|
13972
|
-
const { config: wsConfig } = await client.getWorkspaceModelConfig(workspaceId);
|
|
13973
|
-
return wsConfig
|
|
14084
|
+
const { config: wsConfig, platformDefaults } = await client.getWorkspaceModelConfig(workspaceId);
|
|
14085
|
+
return layerPlatformDefaults(platformDefaults, wsConfig);
|
|
13974
14086
|
}) : undefined;
|
|
13975
14087
|
const modelCatalog = daemonConfig ? new WorkspaceModelCache(async () => {
|
|
13976
14088
|
const { models } = await client.getModelCatalog();
|
|
@@ -14037,6 +14149,14 @@ class Pool {
|
|
|
14037
14149
|
await this.emitWaiting(card.id, `Paused — Anthropic API limit, retrying in ~${Math.round(cooldownMs / 1000)}s`);
|
|
14038
14150
|
return;
|
|
14039
14151
|
}
|
|
14152
|
+
const stageHold = classifyStageHold(card, this.stateStore.getStageHold(card.id), Date.now());
|
|
14153
|
+
if (stageHold.kind === "holding") {
|
|
14154
|
+
log36.debug(TAG32, `#${card.short_id} held — ${stageHold.detail}`);
|
|
14155
|
+
return;
|
|
14156
|
+
}
|
|
14157
|
+
if (stageHold.kind === "stale") {
|
|
14158
|
+
await this.stateStore.clearStageHold(card.id);
|
|
14159
|
+
}
|
|
14040
14160
|
const decision = this.budget.check(card.id);
|
|
14041
14161
|
if (!decision.allow) {
|
|
14042
14162
|
if (decision.reason === "daily_budget") {
|
|
@@ -14735,6 +14855,7 @@ var init_pool = __esm(() => {
|
|
|
14735
14855
|
init_unblock();
|
|
14736
14856
|
init_worker();
|
|
14737
14857
|
init_workspace_model_cache();
|
|
14858
|
+
init_workspace_model_config();
|
|
14738
14859
|
});
|
|
14739
14860
|
|
|
14740
14861
|
// src/port-registry.ts
|
|
@@ -14973,6 +15094,8 @@ var init_repo_dirs = __esm(() => {
|
|
|
14973
15094
|
|
|
14974
15095
|
// src/card-trust.ts
|
|
14975
15096
|
function isTrustedCardAuthor(card, trustedAuthors) {
|
|
15097
|
+
if (card.source != null)
|
|
15098
|
+
return false;
|
|
14976
15099
|
return card.created_by != null && trustedAuthors.has(card.created_by);
|
|
14977
15100
|
}
|
|
14978
15101
|
|
|
@@ -15032,7 +15155,7 @@ async function reclaimPreReviewStrands(opts) {
|
|
|
15032
15155
|
continue;
|
|
15033
15156
|
const daemonBranch = daemonBranches.get(card.id);
|
|
15034
15157
|
if (!isTrustedCardAuthor(card, trustedAuthors) && daemonBranch !== branch) {
|
|
15035
|
-
log40.debug(TAG36, `#${card.short_id} - skipped: author ${card.created_by ?? "(none)"} is not trusted, and ${daemonBranch ? `the card records ${branch} while this daemon pushed ${daemonBranch}` : "this daemon has pushed no branch for it"}`);
|
|
15158
|
+
log40.debug(TAG36, `#${card.short_id} - skipped: ${card.source != null ? `card was filed externally (source: ${card.source})` : `author ${card.created_by ?? "(none)"} is not trusted`}, and ${daemonBranch ? `the card records ${branch} while this daemon pushed ${daemonBranch}` : "this daemon has pushed no branch for it"}`);
|
|
15036
15159
|
continue;
|
|
15037
15160
|
}
|
|
15038
15161
|
const labels = resolveCardLabels(card, labelMap);
|
|
@@ -15270,7 +15393,7 @@ function rankSweepCandidates(opts) {
|
|
|
15270
15393
|
continue;
|
|
15271
15394
|
}
|
|
15272
15395
|
if (!isTrustedCardAuthor(card, trustedAuthors)) {
|
|
15273
|
-
skip2(card, "untrusted_author", card.created_by == null ? "card has no recorded author" : `author ${card.created_by} is not in sweep.trustedAuthors`);
|
|
15396
|
+
skip2(card, "untrusted_author", card.source != null ? `card was filed externally (source: ${card.source})` : card.created_by == null ? "card has no recorded author" : `author ${card.created_by} is not in sweep.trustedAuthors`);
|
|
15274
15397
|
continue;
|
|
15275
15398
|
}
|
|
15276
15399
|
if (card.assigned_agent_id != null) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gethmy/agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.46.0",
|
|
4
4
|
"description": "Push-based agent daemon for Harmony — picks up assigned cards, builds them in isolated git worktrees, and opens PRs. It runs where you put it.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@anthropic-ai/claude-agent-sdk": "^0.3.178",
|
|
48
|
-
"@gethmy/harness": "1.19.
|
|
49
|
-
"@gethmy/mcp": "3.
|
|
48
|
+
"@gethmy/harness": "1.19.1",
|
|
49
|
+
"@gethmy/mcp": "3.16.0",
|
|
50
50
|
"@supabase/supabase-js": "2.95.3"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|