@gethmy/agent 1.7.1 → 1.7.3

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.
Files changed (77) hide show
  1. package/dist/cli.js +6386 -141
  2. package/dist/index.js +6216 -333
  3. package/package.json +2 -2
  4. package/dist/board-helpers.d.ts +0 -31
  5. package/dist/board-helpers.js +0 -150
  6. package/dist/budget.d.ts +0 -39
  7. package/dist/budget.js +0 -73
  8. package/dist/cli.d.ts +0 -14
  9. package/dist/completion.d.ts +0 -36
  10. package/dist/completion.js +0 -322
  11. package/dist/config-validation.d.ts +0 -23
  12. package/dist/config-validation.js +0 -77
  13. package/dist/config.d.ts +0 -23
  14. package/dist/config.js +0 -103
  15. package/dist/episode-writer.d.ts +0 -116
  16. package/dist/episode-writer.js +0 -349
  17. package/dist/git-diff-stat.d.ts +0 -24
  18. package/dist/git-diff-stat.js +0 -56
  19. package/dist/git-pr.d.ts +0 -38
  20. package/dist/git-pr.js +0 -399
  21. package/dist/http-server.d.ts +0 -66
  22. package/dist/http-server.js +0 -96
  23. package/dist/index.d.ts +0 -5
  24. package/dist/log.d.ts +0 -34
  25. package/dist/log.js +0 -100
  26. package/dist/merge-monitor.d.ts +0 -23
  27. package/dist/merge-monitor.js +0 -169
  28. package/dist/pm.d.ts +0 -14
  29. package/dist/pm.js +0 -63
  30. package/dist/pool.d.ts +0 -71
  31. package/dist/pool.js +0 -259
  32. package/dist/process-group.d.ts +0 -26
  33. package/dist/process-group.js +0 -72
  34. package/dist/progress-tracker.d.ts +0 -82
  35. package/dist/progress-tracker.js +0 -457
  36. package/dist/prompt.d.ts +0 -23
  37. package/dist/prompt.js +0 -160
  38. package/dist/queue.d.ts +0 -39
  39. package/dist/queue.js +0 -100
  40. package/dist/reconcile.d.ts +0 -35
  41. package/dist/reconcile.js +0 -174
  42. package/dist/recovery.d.ts +0 -30
  43. package/dist/recovery.js +0 -141
  44. package/dist/review-completion.d.ts +0 -35
  45. package/dist/review-completion.js +0 -475
  46. package/dist/review-knowledge.d.ts +0 -14
  47. package/dist/review-knowledge.js +0 -89
  48. package/dist/review-prompt.d.ts +0 -12
  49. package/dist/review-prompt.js +0 -103
  50. package/dist/review-worker.d.ts +0 -56
  51. package/dist/review-worker.js +0 -638
  52. package/dist/review-worktree.d.ts +0 -12
  53. package/dist/review-worktree.js +0 -95
  54. package/dist/run-log.d.ts +0 -6
  55. package/dist/run-log.js +0 -19
  56. package/dist/startup-banner.d.ts +0 -29
  57. package/dist/startup-banner.js +0 -143
  58. package/dist/state-store.d.ts +0 -89
  59. package/dist/state-store.js +0 -230
  60. package/dist/stream-parser-selftest.d.ts +0 -9
  61. package/dist/stream-parser-selftest.js +0 -97
  62. package/dist/stream-parser.d.ts +0 -43
  63. package/dist/stream-parser.js +0 -174
  64. package/dist/transitions.d.ts +0 -57
  65. package/dist/transitions.js +0 -131
  66. package/dist/types.d.ts +0 -167
  67. package/dist/types.js +0 -76
  68. package/dist/verification.d.ts +0 -39
  69. package/dist/verification.js +0 -317
  70. package/dist/watcher.d.ts +0 -53
  71. package/dist/watcher.js +0 -153
  72. package/dist/worker.d.ts +0 -54
  73. package/dist/worker.js +0 -507
  74. package/dist/worktree-gc.d.ts +0 -67
  75. package/dist/worktree-gc.js +0 -245
  76. package/dist/worktree.d.ts +0 -18
  77. package/dist/worktree.js +0 -177
package/dist/git-pr.js DELETED
@@ -1,399 +0,0 @@
1
- import { execFile, execFileSync } from "node:child_process";
2
- import { promisify } from "node:util";
3
- import { log } from "./log.js";
4
- const execFileAsync = promisify(execFile);
5
- const TAG = "git-pr";
6
- export function detectGitProvider(cwd) {
7
- try {
8
- const url = execFileSync("git", ["remote", "get-url", "origin"], {
9
- cwd,
10
- encoding: "utf-8",
11
- }).trim();
12
- if (url.includes("github.com"))
13
- return "github";
14
- if (url.includes("dev.azure.com") || url.includes("visualstudio.com"))
15
- return "azure";
16
- if (url.includes("gitlab.com") || /\bgitlab\b/.test(url))
17
- return "gitlab";
18
- if (url.includes("bitbucket.org"))
19
- return "bitbucket";
20
- return "unknown";
21
- }
22
- catch {
23
- return "unknown";
24
- }
25
- }
26
- /**
27
- * Validate that the CLI for the detected git provider is installed and authenticated.
28
- * Returns the provider name or throws with instructions.
29
- */
30
- export function validateGitProviderCli(provider, cwd) {
31
- switch (provider) {
32
- case "github": {
33
- try {
34
- execFileSync("gh", ["auth", "status"], { cwd, stdio: "pipe" });
35
- }
36
- catch {
37
- throw new Error("GitHub CLI (gh) is not authenticated. Run: gh auth login");
38
- }
39
- break;
40
- }
41
- case "azure": {
42
- try {
43
- execFileSync("az", ["--version"], { cwd, stdio: "pipe" });
44
- }
45
- catch {
46
- throw new Error("Azure CLI (az) not found. Install it: https://learn.microsoft.com/en-us/cli/azure/install-azure-cli");
47
- }
48
- try {
49
- execFileSync("az", ["account", "show"], { cwd, stdio: "pipe" });
50
- }
51
- catch {
52
- throw new Error("Azure CLI is not authenticated. Run: az login");
53
- }
54
- break;
55
- }
56
- case "gitlab": {
57
- try {
58
- execFileSync("glab", ["auth", "status"], { cwd, stdio: "pipe" });
59
- }
60
- catch {
61
- throw new Error("GitLab CLI (glab) is not installed or not authenticated. Install: https://gitlab.com/gitlab-org/cli — then run: glab auth login");
62
- }
63
- break;
64
- }
65
- case "bitbucket":
66
- case "unknown":
67
- log.warn(TAG, `Git provider "${provider}" — PR creation will be skipped (no CLI support)`);
68
- break;
69
- }
70
- }
71
- const VALID_PR_URL_RE = /^https:\/\/(github\.com|gitlab\.com|dev\.azure\.com|bitbucket\.org)\//;
72
- const PR_URL_RE = /PR:\s*(https?:\/\/[^\s)]+)/;
73
- /** Validate that a PR URL looks like a real provider URL. */
74
- function isValidPrUrl(url) {
75
- return VALID_PR_URL_RE.test(url);
76
- }
77
- /**
78
- * Check whether a PR has been merged using the git provider CLI (async).
79
- */
80
- export async function checkPrMergeStatus(prUrl, cwd, provider) {
81
- if (!isValidPrUrl(prUrl))
82
- return "unknown";
83
- try {
84
- switch (provider) {
85
- case "github": {
86
- const { stdout } = await execFileAsync("gh", ["pr", "view", prUrl, "--json", "state", "--jq", ".state"], { cwd, encoding: "utf-8", timeout: 10_000 });
87
- switch (stdout.trim()) {
88
- case "MERGED":
89
- return "merged";
90
- case "OPEN":
91
- return "open";
92
- case "CLOSED":
93
- return "closed";
94
- default:
95
- return "unknown";
96
- }
97
- }
98
- case "gitlab": {
99
- // Extract MR ID from URL (e.g. .../merge_requests/42)
100
- const mrMatch = prUrl.match(/merge_requests\/(\d+)/);
101
- if (!mrMatch)
102
- return "unknown";
103
- const { stdout } = await execFileAsync("glab", ["mr", "view", mrMatch[1], "--output", "json"], { cwd, encoding: "utf-8", timeout: 10_000 });
104
- let parsed;
105
- try {
106
- parsed = JSON.parse(stdout.trim());
107
- }
108
- catch {
109
- log.warn(TAG, `Failed to parse glab JSON output for MR ${mrMatch[1]}`);
110
- return "unknown";
111
- }
112
- if (typeof parsed !== "object" || parsed === null)
113
- return "unknown";
114
- const state = parsed.state;
115
- if (state === "merged")
116
- return "merged";
117
- if (state === "opened")
118
- return "open";
119
- if (state === "closed")
120
- return "closed";
121
- return "unknown";
122
- }
123
- default:
124
- return "unknown";
125
- }
126
- }
127
- catch {
128
- return "unknown";
129
- }
130
- }
131
- /**
132
- * Extract a PR URL from card description. Matches the format written by completion.ts:
133
- * `PR: https://...`
134
- */
135
- export function extractPrUrl(description) {
136
- if (!description)
137
- return null;
138
- const match = description.match(PR_URL_RE);
139
- if (!match)
140
- return null;
141
- try {
142
- return new URL(match[1]).href;
143
- }
144
- catch {
145
- return null;
146
- }
147
- }
148
- // ============ PUSH (REWORK-AWARE) ============
149
- export function remoteBranchExists(branchName, cwd) {
150
- try {
151
- execFileSync("git", ["ls-remote", "--exit-code", "origin", `refs/heads/${branchName}`], { cwd, stdio: "pipe" });
152
- return true;
153
- }
154
- catch {
155
- return false;
156
- }
157
- }
158
- export function pushBranch(branchName, cwd) {
159
- if (remoteBranchExists(branchName, cwd)) {
160
- log.info(TAG, `Remote branch ${branchName} exists (rework), force-pushing`);
161
- // Resolve the remote tip explicitly so the lease anchors to a known SHA.
162
- // Bare `--force-with-lease` only checks against the local tracking ref,
163
- // which can be stale if it was never fetched in this worktree — that
164
- // lets a concurrent update slip through. Fetch + pin the expected SHA.
165
- let expectedSha = null;
166
- try {
167
- execFileSync("git", ["fetch", "origin", branchName], {
168
- cwd,
169
- stdio: "pipe",
170
- });
171
- expectedSha = execFileSync("git", ["rev-parse", `refs/remotes/origin/${branchName}`], { cwd, encoding: "utf-8" }).trim();
172
- }
173
- catch (err) {
174
- log.warn(TAG, `could not resolve remote tip for ${branchName}, falling back to weak lease: ${err instanceof Error ? err.message : err}`);
175
- }
176
- const lease = expectedSha
177
- ? `--force-with-lease=refs/heads/${branchName}:${expectedSha}`
178
- : "--force-with-lease";
179
- execFileSync("git", ["push", lease, "-u", "origin", branchName], {
180
- cwd,
181
- stdio: "pipe",
182
- });
183
- }
184
- else {
185
- execFileSync("git", ["push", "-u", "origin", branchName], {
186
- cwd,
187
- stdio: "pipe",
188
- });
189
- }
190
- }
191
- /**
192
- * Push the current branch's tip to `newRef` on origin and delete `oldRef`.
193
- * Used when an approved attempt graduates from `agent-attempts/*` to
194
- * `agent/*` — keeps the commits durable across the rename and avoids any
195
- * window where the work is unreachable on origin.
196
- */
197
- export function renameRemoteBranch(oldRef, newRef, cwd) {
198
- if (oldRef === newRef)
199
- return;
200
- let sha;
201
- try {
202
- sha = execFileSync("git", ["rev-parse", "HEAD"], {
203
- cwd,
204
- encoding: "utf-8",
205
- }).trim();
206
- }
207
- catch (err) {
208
- throw new Error(`renameRemoteBranch: could not resolve HEAD: ${err instanceof Error ? err.message : err}`);
209
- }
210
- log.info(TAG, `Renaming remote ${oldRef} → ${newRef}`);
211
- execFileSync("git", ["push", "origin", `${sha}:refs/heads/${newRef}`, "--force-with-lease"], { cwd, stdio: "pipe" });
212
- try {
213
- execFileSync("git", ["push", "origin", `:refs/heads/${oldRef}`], {
214
- cwd,
215
- stdio: "pipe",
216
- });
217
- }
218
- catch (err) {
219
- log.warn(TAG, `renameRemoteBranch: could not delete old ref ${oldRef}: ${err instanceof Error ? err.message : err}`);
220
- }
221
- try {
222
- execFileSync("git", ["branch", "-m", oldRef, newRef], {
223
- cwd,
224
- stdio: "pipe",
225
- });
226
- }
227
- catch {
228
- // Worktree may not have the old branch checked out — non-fatal.
229
- }
230
- }
231
- /**
232
- * Best-effort public branch URL for the recovery button on a failed session.
233
- * Returns null when we can't infer a tree URL — the daemon falls back to a
234
- * plain `git fetch && git checkout <ref>` instruction in that case.
235
- */
236
- export function getBranchWebUrl(branchName, cwd) {
237
- try {
238
- const remoteUrl = execFileSync("git", ["remote", "get-url", "origin"], {
239
- cwd,
240
- encoding: "utf-8",
241
- }).trim();
242
- const encoded = branchName.split("/").map(encodeURIComponent).join("/");
243
- if (/github\.com[:/]([^/]+)\/([^/.]+)/.test(remoteUrl)) {
244
- const m = remoteUrl.match(/github\.com[:/]([^/]+)\/([^/.]+?)(?:\.git)?$/);
245
- if (m)
246
- return `https://github.com/${m[1]}/${m[2]}/tree/${encoded}`;
247
- }
248
- if (/gitlab\.com[:/]([^/]+)\/([^/.]+)/.test(remoteUrl)) {
249
- const m = remoteUrl.match(/gitlab\.com[:/](.+?)(?:\.git)?$/);
250
- if (m)
251
- return `https://gitlab.com/${m[1]}/-/tree/${encoded}`;
252
- }
253
- if (/bitbucket\.org[:/]([^/]+)\/([^/.]+)/.test(remoteUrl)) {
254
- const m = remoteUrl.match(/bitbucket\.org[:/](.+?)(?:\.git)?$/);
255
- if (m)
256
- return `https://bitbucket.org/${m[1]}/branch/${encoded}`;
257
- }
258
- return null;
259
- }
260
- catch {
261
- return null;
262
- }
263
- }
264
- // ============ PR CREATION (PROVIDER-AWARE) ============
265
- export function buildPrBody(card, commitLog) {
266
- return [
267
- "## Summary",
268
- "",
269
- `Automated PR for card **#${card.short_id} — ${card.title}**.`,
270
- "",
271
- "## Commits",
272
- "",
273
- "```",
274
- commitLog,
275
- "```",
276
- "",
277
- "## Card",
278
- "",
279
- card.description?.slice(0, 500) || "No description.",
280
- "",
281
- "---",
282
- "*Created by Harmony Agent Daemon*",
283
- ].join("\n");
284
- }
285
- export function createPullRequest(card, branchName, worktreePath, config, provider) {
286
- let commitLog = "";
287
- try {
288
- commitLog = execFileSync("git", ["log", "--oneline", `origin/${config.worktree.baseBranch}..HEAD`], { cwd: worktreePath, encoding: "utf-8" }).trim();
289
- }
290
- catch {
291
- commitLog = "(unable to retrieve commit log)";
292
- }
293
- const title = `#${card.short_id} ${card.title}`;
294
- const body = buildPrBody(card, commitLog);
295
- const base = config.worktree.baseBranch;
296
- // Check for existing PR first (rework case)
297
- const existingUrl = findExistingPr(branchName, worktreePath, provider);
298
- if (existingUrl) {
299
- log.info(TAG, `PR already exists for ${branchName}, updating body...`);
300
- updateExistingPr(branchName, body, worktreePath, provider);
301
- return existingUrl;
302
- }
303
- // No existing PR — create a new one
304
- try {
305
- let result;
306
- switch (provider) {
307
- case "github":
308
- result = execFileSync("gh", ["pr", "create", "--title", title, "--body", body, "--base", base], { cwd: worktreePath, encoding: "utf-8" }).trim();
309
- break;
310
- case "azure": {
311
- const azOutput = execFileSync("az", [
312
- "repos",
313
- "pr",
314
- "create",
315
- "--title",
316
- title,
317
- "--description",
318
- body,
319
- "--source-branch",
320
- branchName,
321
- "--target-branch",
322
- base,
323
- "--auto-complete",
324
- "false",
325
- ], { cwd: worktreePath, encoding: "utf-8" }).trim();
326
- // az repos pr create returns JSON — extract the URL
327
- try {
328
- const parsed = JSON.parse(azOutput);
329
- result = parsed.remoteUrl ?? parsed.url ?? azOutput;
330
- }
331
- catch {
332
- result = azOutput;
333
- }
334
- break;
335
- }
336
- case "gitlab":
337
- result = execFileSync("glab", [
338
- "mr",
339
- "create",
340
- "--title",
341
- title,
342
- "--description",
343
- body,
344
- "--source-branch",
345
- branchName,
346
- "--target-branch",
347
- base,
348
- "--no-editor",
349
- ], { cwd: worktreePath, encoding: "utf-8" }).trim();
350
- break;
351
- default:
352
- log.warn(TAG, `No PR CLI for provider "${provider}" — branch pushed but no PR created`);
353
- return null;
354
- }
355
- log.info(TAG, `PR created: ${result}`);
356
- return result;
357
- }
358
- catch (err) {
359
- log.error(TAG, `Failed to create PR: ${err instanceof Error ? err.message : err}`);
360
- return null;
361
- }
362
- }
363
- export function findExistingPr(branchName, worktreePath, provider) {
364
- try {
365
- switch (provider) {
366
- case "github":
367
- return execFileSync("gh", ["pr", "view", branchName, "--json", "url", "--jq", ".url"], { cwd: worktreePath, encoding: "utf-8" }).trim();
368
- case "gitlab": {
369
- const json = execFileSync("glab", ["mr", "view", branchName, "--output", "json"], { cwd: worktreePath, encoding: "utf-8" }).trim();
370
- const parsed = JSON.parse(json);
371
- return parsed.web_url || null;
372
- }
373
- default:
374
- return null;
375
- }
376
- }
377
- catch {
378
- return null;
379
- }
380
- }
381
- export function updateExistingPr(branchName, body, worktreePath, provider) {
382
- try {
383
- switch (provider) {
384
- case "github":
385
- execFileSync("gh", ["pr", "edit", branchName, "--body", body], {
386
- cwd: worktreePath,
387
- stdio: "pipe",
388
- });
389
- break;
390
- case "gitlab":
391
- execFileSync("glab", ["mr", "update", branchName, "--description", body], { cwd: worktreePath, stdio: "pipe" });
392
- break;
393
- }
394
- log.info(TAG, `Updated existing PR body for ${branchName}`);
395
- }
396
- catch (err) {
397
- log.warn(TAG, `Failed to update PR body: ${err instanceof Error ? err.message : err}`);
398
- }
399
- }
@@ -1,66 +0,0 @@
1
- export interface HealthSnapshot {
2
- healthy: boolean;
3
- checks: Record<string, boolean>;
4
- }
5
- export interface WorkerSnapshot {
6
- id: number;
7
- pipeline: "implement" | "review";
8
- state: string;
9
- cardId: string | null;
10
- cardShortId: number | null;
11
- phase: string | null;
12
- startedAt: number | null;
13
- branchName: string | null;
14
- }
15
- export interface StatusSnapshot {
16
- daemonId: string;
17
- daemonPid: number;
18
- startedAt: number;
19
- uptimeMs: number;
20
- workers: WorkerSnapshot[];
21
- implQueue: Array<{
22
- cardId: string;
23
- shortId: number;
24
- priority: number;
25
- enqueuedAt: number;
26
- }>;
27
- reviewQueue: Array<{
28
- cardId: string;
29
- shortId: number;
30
- priority: number;
31
- enqueuedAt: number;
32
- }>;
33
- budget: {
34
- todayCents: number;
35
- dailyCapCents: number;
36
- };
37
- }
38
- export type Command = "pause" | "resume" | "stop";
39
- export interface HttpServerOptions {
40
- port: number;
41
- bindAddr: string;
42
- getStatus: () => StatusSnapshot;
43
- getHealth: () => HealthSnapshot;
44
- handleCommand: (cmd: Command, cardId: string) => Promise<void>;
45
- }
46
- /**
47
- * Tiny introspection + control surface for the running daemon.
48
- * Binds to 127.0.0.1 by default so it's not network-reachable.
49
- *
50
- * GET /health — 200 when healthy, 503 otherwise. Simple liveness check
51
- * suitable for process supervisors (systemd, pm2, docker healthcheck).
52
- * GET /status — full JSON snapshot: workers, queues, budget.
53
- * POST /pause/:cardId, /resume/:cardId, /stop/:cardId — command path
54
- * so an operator can nudge a stuck worker without killing the daemon.
55
- */
56
- export declare class HttpServer {
57
- private opts;
58
- private server;
59
- constructor(opts: HttpServerOptions);
60
- start(): Promise<void>;
61
- stop(): Promise<void>;
62
- private route;
63
- private respondHealth;
64
- private respondStatus;
65
- private respondCommand;
66
- }
@@ -1,96 +0,0 @@
1
- import { createServer, } from "node:http";
2
- import { log } from "./log.js";
3
- const TAG = "http";
4
- /**
5
- * Tiny introspection + control surface for the running daemon.
6
- * Binds to 127.0.0.1 by default so it's not network-reachable.
7
- *
8
- * GET /health — 200 when healthy, 503 otherwise. Simple liveness check
9
- * suitable for process supervisors (systemd, pm2, docker healthcheck).
10
- * GET /status — full JSON snapshot: workers, queues, budget.
11
- * POST /pause/:cardId, /resume/:cardId, /stop/:cardId — command path
12
- * so an operator can nudge a stuck worker without killing the daemon.
13
- */
14
- export class HttpServer {
15
- opts;
16
- server = null;
17
- constructor(opts) {
18
- this.opts = opts;
19
- }
20
- async start() {
21
- return new Promise((resolve, reject) => {
22
- this.server = createServer((req, res) => {
23
- this.route(req, res).catch((err) => {
24
- log.error(TAG, `unhandled: ${err instanceof Error ? err.message : err}`);
25
- if (!res.headersSent) {
26
- res.writeHead(500, { "content-type": "application/json" });
27
- res.end(JSON.stringify({ error: "internal_error" }));
28
- }
29
- });
30
- });
31
- this.server.once("error", reject);
32
- this.server.listen(this.opts.port, this.opts.bindAddr, () => {
33
- resolve();
34
- });
35
- });
36
- }
37
- async stop() {
38
- if (!this.server)
39
- return;
40
- await new Promise((resolve) => {
41
- this.server?.close(() => resolve());
42
- });
43
- this.server = null;
44
- }
45
- async route(req, res) {
46
- const url = new URL(req.url ?? "/", "http://localhost");
47
- const method = (req.method ?? "GET").toUpperCase();
48
- const path = url.pathname;
49
- if (method === "GET" && path === "/health") {
50
- return this.respondHealth(res);
51
- }
52
- if (method === "GET" && path === "/status") {
53
- return this.respondStatus(res);
54
- }
55
- if (method === "POST") {
56
- const cmd = parseCommand(path);
57
- if (cmd) {
58
- return this.respondCommand(res, cmd.command, cmd.cardId);
59
- }
60
- }
61
- res.writeHead(404, { "content-type": "application/json" });
62
- res.end(JSON.stringify({ error: "not_found", path }));
63
- }
64
- respondHealth(res) {
65
- const health = this.opts.getHealth();
66
- res.writeHead(health.healthy ? 200 : 503, {
67
- "content-type": "application/json",
68
- });
69
- res.end(JSON.stringify(health));
70
- }
71
- respondStatus(res) {
72
- const snapshot = this.opts.getStatus();
73
- res.writeHead(200, { "content-type": "application/json" });
74
- res.end(JSON.stringify(snapshot));
75
- }
76
- async respondCommand(res, command, cardId) {
77
- try {
78
- await this.opts.handleCommand(command, cardId);
79
- res.writeHead(200, { "content-type": "application/json" });
80
- res.end(JSON.stringify({ ok: true, command, cardId }));
81
- }
82
- catch (err) {
83
- res.writeHead(500, { "content-type": "application/json" });
84
- res.end(JSON.stringify({
85
- error: "command_failed",
86
- detail: err instanceof Error ? err.message : String(err),
87
- }));
88
- }
89
- }
90
- }
91
- function parseCommand(path) {
92
- const match = path.match(/^\/(pause|resume|stop)\/([^/]+)$/);
93
- if (!match)
94
- return null;
95
- return { command: match[1], cardId: decodeURIComponent(match[2]) };
96
- }
package/dist/index.d.ts DELETED
@@ -1,5 +0,0 @@
1
- import { type DaemonConfig } from "./config.js";
2
- import { type StartupBanner } from "./startup-banner.js";
3
- declare function validatePrerequisites(config: DaemonConfig, banner: StartupBanner): Promise<string>;
4
- export { validatePrerequisites };
5
- export declare function main(): Promise<void>;
package/dist/log.d.ts DELETED
@@ -1,34 +0,0 @@
1
- /**
2
- * Structured logging for the agent daemon.
3
- *
4
- * When stderr is a TTY, output is ANSI-coloured single-line text — the
5
- * readable default for humans running the daemon interactively. When
6
- * stderr is piped/redirected (files, logshippers, systemd), output
7
- * falls back to one JSON object per line — trivially `jq`-able,
8
- * indexable, and machine-readable.
9
- *
10
- * Overrides: `--pretty` / HARMONY_AGENT_PRETTY=1 force pretty;
11
- * `--json` / HARMONY_AGENT_JSON=1 force JSON. Explicit flags beat
12
- * TTY detection either way.
13
- *
14
- * Stdout is left clean so consumers can pipe structured data if they
15
- * want to (future use).
16
- */
17
- export interface LogContext {
18
- event?: string;
19
- runId?: string;
20
- cardId?: string;
21
- [key: string]: unknown;
22
- }
23
- export declare const log: {
24
- info(tag: string, msg: string, ctx?: LogContext): void;
25
- warn(tag: string, msg: string, ctx?: LogContext): void;
26
- error(tag: string, msg: string, ctx?: LogContext): void;
27
- debug(tag: string, msg: string, ctx?: LogContext): void;
28
- /**
29
- * Emit a named event. Semantically the same as `info` but signals to
30
- * downstream tooling that this is a structured event worth indexing.
31
- */
32
- event(tag: string, event: string, ctx?: LogContext): void;
33
- };
34
- export declare function isPretty(): boolean;