@laurentenhoor/devclaw 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.
Files changed (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +406 -0
  3. package/dist/index.d.ts +88 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +107 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/lib/audit.d.ts +2 -0
  8. package/dist/lib/audit.d.ts.map +1 -0
  9. package/dist/lib/audit.js +42 -0
  10. package/dist/lib/audit.js.map +1 -0
  11. package/dist/lib/binding-manager.d.ts +35 -0
  12. package/dist/lib/binding-manager.d.ts.map +1 -0
  13. package/dist/lib/binding-manager.js +88 -0
  14. package/dist/lib/binding-manager.js.map +1 -0
  15. package/dist/lib/cli.d.ts +12 -0
  16. package/dist/lib/cli.d.ts.map +1 -0
  17. package/dist/lib/cli.js +69 -0
  18. package/dist/lib/cli.js.map +1 -0
  19. package/dist/lib/dispatch.d.ts +58 -0
  20. package/dist/lib/dispatch.d.ts.map +1 -0
  21. package/dist/lib/dispatch.js +163 -0
  22. package/dist/lib/dispatch.js.map +1 -0
  23. package/dist/lib/model-selector.d.ts +21 -0
  24. package/dist/lib/model-selector.d.ts.map +1 -0
  25. package/dist/lib/model-selector.js +74 -0
  26. package/dist/lib/model-selector.js.map +1 -0
  27. package/dist/lib/notify.d.ts +54 -0
  28. package/dist/lib/notify.d.ts.map +1 -0
  29. package/dist/lib/notify.js +143 -0
  30. package/dist/lib/notify.js.map +1 -0
  31. package/dist/lib/onboarding.d.ts +5 -0
  32. package/dist/lib/onboarding.d.ts.map +1 -0
  33. package/dist/lib/onboarding.js +124 -0
  34. package/dist/lib/onboarding.js.map +1 -0
  35. package/dist/lib/projects.d.ts +64 -0
  36. package/dist/lib/projects.d.ts.map +1 -0
  37. package/dist/lib/projects.js +127 -0
  38. package/dist/lib/projects.js.map +1 -0
  39. package/dist/lib/providers/github.d.ts +23 -0
  40. package/dist/lib/providers/github.d.ts.map +1 -0
  41. package/dist/lib/providers/github.js +130 -0
  42. package/dist/lib/providers/github.js.map +1 -0
  43. package/dist/lib/providers/gitlab.d.ts +23 -0
  44. package/dist/lib/providers/gitlab.d.ts.map +1 -0
  45. package/dist/lib/providers/gitlab.js +133 -0
  46. package/dist/lib/providers/gitlab.js.map +1 -0
  47. package/dist/lib/providers/index.d.ts +12 -0
  48. package/dist/lib/providers/index.d.ts.map +1 -0
  49. package/dist/lib/providers/index.js +25 -0
  50. package/dist/lib/providers/index.js.map +1 -0
  51. package/dist/lib/providers/provider.d.ts +35 -0
  52. package/dist/lib/providers/provider.d.ts.map +1 -0
  53. package/dist/lib/providers/provider.js +13 -0
  54. package/dist/lib/providers/provider.js.map +1 -0
  55. package/dist/lib/services/health.d.ts +38 -0
  56. package/dist/lib/services/health.d.ts.map +1 -0
  57. package/dist/lib/services/health.js +100 -0
  58. package/dist/lib/services/health.js.map +1 -0
  59. package/dist/lib/services/heartbeat.d.ts +38 -0
  60. package/dist/lib/services/heartbeat.d.ts.map +1 -0
  61. package/dist/lib/services/heartbeat.js +199 -0
  62. package/dist/lib/services/heartbeat.js.map +1 -0
  63. package/dist/lib/services/pipeline.d.ts +36 -0
  64. package/dist/lib/services/pipeline.d.ts.map +1 -0
  65. package/dist/lib/services/pipeline.js +90 -0
  66. package/dist/lib/services/pipeline.js.map +1 -0
  67. package/dist/lib/services/queue.d.ts +14 -0
  68. package/dist/lib/services/queue.d.ts.map +1 -0
  69. package/dist/lib/services/queue.js +31 -0
  70. package/dist/lib/services/queue.js.map +1 -0
  71. package/dist/lib/services/tick.d.ts +62 -0
  72. package/dist/lib/services/tick.d.ts.map +1 -0
  73. package/dist/lib/services/tick.js +160 -0
  74. package/dist/lib/services/tick.js.map +1 -0
  75. package/dist/lib/setup/agent.d.ts +14 -0
  76. package/dist/lib/setup/agent.d.ts.map +1 -0
  77. package/dist/lib/setup/agent.js +72 -0
  78. package/dist/lib/setup/agent.js.map +1 -0
  79. package/dist/lib/setup/config.d.ts +22 -0
  80. package/dist/lib/setup/config.d.ts.map +1 -0
  81. package/dist/lib/setup/config.js +67 -0
  82. package/dist/lib/setup/config.js.map +1 -0
  83. package/dist/lib/setup/index.d.ts +53 -0
  84. package/dist/lib/setup/index.d.ts.map +1 -0
  85. package/dist/lib/setup/index.js +68 -0
  86. package/dist/lib/setup/index.js.map +1 -0
  87. package/dist/lib/setup/workspace.d.ts +6 -0
  88. package/dist/lib/setup/workspace.d.ts.map +1 -0
  89. package/dist/lib/setup/workspace.js +69 -0
  90. package/dist/lib/setup/workspace.js.map +1 -0
  91. package/dist/lib/templates.d.ts +9 -0
  92. package/dist/lib/templates.d.ts.map +1 -0
  93. package/dist/lib/templates.js +163 -0
  94. package/dist/lib/templates.js.map +1 -0
  95. package/dist/lib/tiers.d.ts +55 -0
  96. package/dist/lib/tiers.d.ts.map +1 -0
  97. package/dist/lib/tiers.js +74 -0
  98. package/dist/lib/tiers.js.map +1 -0
  99. package/dist/lib/tool-helpers.d.ts +44 -0
  100. package/dist/lib/tool-helpers.d.ts.map +1 -0
  101. package/dist/lib/tool-helpers.js +65 -0
  102. package/dist/lib/tool-helpers.js.map +1 -0
  103. package/dist/lib/tools/health.d.ts +28 -0
  104. package/dist/lib/tools/health.d.ts.map +1 -0
  105. package/dist/lib/tools/health.js +61 -0
  106. package/dist/lib/tools/health.js.map +1 -0
  107. package/dist/lib/tools/onboard.d.ts +24 -0
  108. package/dist/lib/tools/onboard.d.ts.map +1 -0
  109. package/dist/lib/tools/onboard.js +27 -0
  110. package/dist/lib/tools/onboard.js.map +1 -0
  111. package/dist/lib/tools/project-register.d.ts +51 -0
  112. package/dist/lib/tools/project-register.d.ts.map +1 -0
  113. package/dist/lib/tools/project-register.js +172 -0
  114. package/dist/lib/tools/project-register.js.map +1 -0
  115. package/dist/lib/tools/queue-status.test.d.ts +2 -0
  116. package/dist/lib/tools/queue-status.test.d.ts.map +1 -0
  117. package/dist/lib/tools/queue-status.test.js +48 -0
  118. package/dist/lib/tools/queue-status.test.js.map +1 -0
  119. package/dist/lib/tools/setup.d.ts +76 -0
  120. package/dist/lib/tools/setup.d.ts.map +1 -0
  121. package/dist/lib/tools/setup.js +102 -0
  122. package/dist/lib/tools/setup.js.map +1 -0
  123. package/dist/lib/tools/status.d.ts +24 -0
  124. package/dist/lib/tools/status.d.ts.map +1 -0
  125. package/dist/lib/tools/status.js +53 -0
  126. package/dist/lib/tools/status.js.map +1 -0
  127. package/dist/lib/tools/task-comment.d.ts +40 -0
  128. package/dist/lib/tools/task-comment.d.ts.map +1 -0
  129. package/dist/lib/tools/task-comment.js +84 -0
  130. package/dist/lib/tools/task-comment.js.map +1 -0
  131. package/dist/lib/tools/task-create.d.ts +54 -0
  132. package/dist/lib/tools/task-create.d.ts.map +1 -0
  133. package/dist/lib/tools/task-create.js +77 -0
  134. package/dist/lib/tools/task-create.js.map +1 -0
  135. package/dist/lib/tools/task-update.d.ts +40 -0
  136. package/dist/lib/tools/task-update.d.ts.map +1 -0
  137. package/dist/lib/tools/task-update.js +79 -0
  138. package/dist/lib/tools/task-update.js.map +1 -0
  139. package/dist/lib/tools/task-update.test.d.ts +7 -0
  140. package/dist/lib/tools/task-update.test.d.ts.map +1 -0
  141. package/dist/lib/tools/task-update.test.js +55 -0
  142. package/dist/lib/tools/task-update.test.js.map +1 -0
  143. package/dist/lib/tools/work-finish.d.ts +43 -0
  144. package/dist/lib/tools/work-finish.d.ts.map +1 -0
  145. package/dist/lib/tools/work-finish.js +77 -0
  146. package/dist/lib/tools/work-finish.js.map +1 -0
  147. package/dist/lib/tools/work-start.d.ts +39 -0
  148. package/dist/lib/tools/work-start.d.ts.map +1 -0
  149. package/dist/lib/tools/work-start.js +129 -0
  150. package/dist/lib/tools/work-start.js.map +1 -0
  151. package/dist/lib/types.d.ts +17 -0
  152. package/dist/lib/types.d.ts.map +1 -0
  153. package/dist/lib/types.js +8 -0
  154. package/dist/lib/types.js.map +1 -0
  155. package/docs/ARCHITECTURE.md +662 -0
  156. package/docs/CONFIGURATION.md +336 -0
  157. package/docs/MANAGEMENT.md +120 -0
  158. package/docs/ONBOARDING.md +251 -0
  159. package/docs/QA_WORKFLOW.md +120 -0
  160. package/docs/ROADMAP.md +96 -0
  161. package/docs/TESTING.md +339 -0
  162. package/docs/TOOLS.md +361 -0
  163. package/package.json +55 -0
@@ -0,0 +1,130 @@
1
+ /**
2
+ * GitHubProvider — IssueProvider implementation using gh CLI.
3
+ */
4
+ import { execFile } from "node:child_process";
5
+ import { promisify } from "node:util";
6
+ import { writeFile, unlink } from "node:fs/promises";
7
+ import { join } from "node:path";
8
+ import { tmpdir } from "node:os";
9
+ import { STATE_LABELS, LABEL_COLORS, } from "./provider.js";
10
+ const execFileAsync = promisify(execFile);
11
+ function toIssue(gh) {
12
+ return {
13
+ iid: gh.number, title: gh.title, description: gh.body ?? "",
14
+ labels: gh.labels.map((l) => l.name), state: gh.state, web_url: gh.url,
15
+ };
16
+ }
17
+ export class GitHubProvider {
18
+ repoPath;
19
+ constructor(opts) { this.repoPath = opts.repoPath; }
20
+ async gh(args) {
21
+ const { stdout } = await execFileAsync("gh", args, { cwd: this.repoPath, timeout: 30_000 });
22
+ return stdout.trim();
23
+ }
24
+ async ensureLabel(name, color) {
25
+ try {
26
+ await this.gh(["label", "create", name, "--color", color.replace(/^#/, "")]);
27
+ }
28
+ catch (err) {
29
+ if (!err.message?.includes("already exists"))
30
+ throw err;
31
+ }
32
+ }
33
+ async ensureAllStateLabels() {
34
+ for (const label of STATE_LABELS)
35
+ await this.ensureLabel(label, LABEL_COLORS[label]);
36
+ }
37
+ async createIssue(title, description, label, assignees) {
38
+ const tempFile = join(tmpdir(), `devclaw-issue-${Date.now()}.md`);
39
+ await writeFile(tempFile, description, "utf-8");
40
+ try {
41
+ const args = ["issue", "create", "--title", title, "--body-file", tempFile, "--label", label];
42
+ if (assignees?.length)
43
+ args.push("--assignee", assignees.join(","));
44
+ const url = await this.gh(args);
45
+ const match = url.match(/\/issues\/(\d+)$/);
46
+ if (!match)
47
+ throw new Error(`Failed to parse issue URL: ${url}`);
48
+ return this.getIssue(parseInt(match[1], 10));
49
+ }
50
+ finally {
51
+ try {
52
+ await unlink(tempFile);
53
+ }
54
+ catch { /* ignore */ }
55
+ }
56
+ }
57
+ async listIssuesByLabel(label) {
58
+ try {
59
+ const raw = await this.gh(["issue", "list", "--label", label, "--state", "open", "--json", "number,title,body,labels,state,url"]);
60
+ return JSON.parse(raw).map(toIssue);
61
+ }
62
+ catch {
63
+ return [];
64
+ }
65
+ }
66
+ async getIssue(issueId) {
67
+ const raw = await this.gh(["issue", "view", String(issueId), "--json", "number,title,body,labels,state,url"]);
68
+ return toIssue(JSON.parse(raw));
69
+ }
70
+ async transitionLabel(issueId, from, to) {
71
+ const issue = await this.getIssue(issueId);
72
+ const stateLabels = issue.labels.filter((l) => STATE_LABELS.includes(l));
73
+ const args = ["issue", "edit", String(issueId)];
74
+ for (const l of stateLabels)
75
+ args.push("--remove-label", l);
76
+ args.push("--add-label", to);
77
+ await this.gh(args);
78
+ }
79
+ async closeIssue(issueId) { await this.gh(["issue", "close", String(issueId)]); }
80
+ async reopenIssue(issueId) { await this.gh(["issue", "reopen", String(issueId)]); }
81
+ hasStateLabel(issue, expected) { return issue.labels.includes(expected); }
82
+ getCurrentStateLabel(issue) {
83
+ return STATE_LABELS.find((l) => issue.labels.includes(l)) ?? null;
84
+ }
85
+ async hasMergedMR(issueId) {
86
+ try {
87
+ const raw = await this.gh(["pr", "list", "--state", "merged", "--json", "title,body"]);
88
+ const prs = JSON.parse(raw);
89
+ const pat = `#${issueId}`;
90
+ return prs.some((pr) => pr.title.includes(pat) || (pr.body ?? "").includes(pat));
91
+ }
92
+ catch {
93
+ return false;
94
+ }
95
+ }
96
+ async getMergedMRUrl(issueId) {
97
+ try {
98
+ const raw = await this.gh(["pr", "list", "--state", "merged", "--json", "number,title,body,url,mergedAt", "--limit", "20"]);
99
+ const prs = JSON.parse(raw);
100
+ const pat = `#${issueId}`;
101
+ return prs.find((pr) => pr.title.includes(pat) || (pr.body ?? "").includes(pat))?.url ?? null;
102
+ }
103
+ catch {
104
+ return null;
105
+ }
106
+ }
107
+ async addComment(issueId, body) {
108
+ const tempFile = join(tmpdir(), `devclaw-comment-${Date.now()}.md`);
109
+ await writeFile(tempFile, body, "utf-8");
110
+ try {
111
+ await this.gh(["issue", "comment", String(issueId), "--body-file", tempFile]);
112
+ }
113
+ finally {
114
+ try {
115
+ await unlink(tempFile);
116
+ }
117
+ catch { /* ignore */ }
118
+ }
119
+ }
120
+ async healthCheck() {
121
+ try {
122
+ await this.gh(["auth", "status"]);
123
+ return true;
124
+ }
125
+ catch {
126
+ return false;
127
+ }
128
+ }
129
+ }
130
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../../../lib/providers/github.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { type IssueProvider, type Issue, type StateLabel } from "./provider.js";
2
+ export declare class GitLabProvider implements IssueProvider {
3
+ private repoPath;
4
+ constructor(opts: {
5
+ repoPath: string;
6
+ });
7
+ private glab;
8
+ ensureLabel(name: string, color: string): Promise<void>;
9
+ ensureAllStateLabels(): Promise<void>;
10
+ createIssue(title: string, description: string, label: StateLabel, assignees?: string[]): Promise<Issue>;
11
+ listIssuesByLabel(label: StateLabel): Promise<Issue[]>;
12
+ getIssue(issueId: number): Promise<Issue>;
13
+ transitionLabel(issueId: number, from: StateLabel, to: StateLabel): Promise<void>;
14
+ closeIssue(issueId: number): Promise<void>;
15
+ reopenIssue(issueId: number): Promise<void>;
16
+ hasStateLabel(issue: Issue, expected: StateLabel): boolean;
17
+ getCurrentStateLabel(issue: Issue): StateLabel | null;
18
+ hasMergedMR(issueId: number): Promise<boolean>;
19
+ getMergedMRUrl(issueId: number): Promise<string | null>;
20
+ addComment(issueId: number, body: string): Promise<void>;
21
+ healthCheck(): Promise<boolean>;
22
+ }
23
+ //# sourceMappingURL=gitlab.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitlab.d.ts","sourceRoot":"","sources":["../../../lib/providers/gitlab.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,UAAU,EAGhB,MAAM,eAAe,CAAC;AAIvB,qBAAa,cAAe,YAAW,aAAa;IAClD,OAAO,CAAC,QAAQ,CAAS;gBACb,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE;YAExB,IAAI;IAKZ,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvD,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;IAgBxG,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAOtD,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAKzC,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IASjF,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAC1C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAEjD,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,GAAG,OAAO;IAC1D,oBAAoB,CAAC,KAAK,EAAE,KAAK,GAAG,UAAU,GAAG,IAAI;IAI/C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS9C,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAYvD,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUxD,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;CAGtC"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * GitLabProvider — IssueProvider implementation using glab CLI.
3
+ */
4
+ import { execFile } from "node:child_process";
5
+ import { promisify } from "node:util";
6
+ import { writeFile, unlink } from "node:fs/promises";
7
+ import { join } from "node:path";
8
+ import { tmpdir } from "node:os";
9
+ import { STATE_LABELS, LABEL_COLORS, } from "./provider.js";
10
+ const execFileAsync = promisify(execFile);
11
+ export class GitLabProvider {
12
+ repoPath;
13
+ constructor(opts) { this.repoPath = opts.repoPath; }
14
+ async glab(args) {
15
+ const { stdout } = await execFileAsync("glab", args, { cwd: this.repoPath, timeout: 30_000 });
16
+ return stdout.trim();
17
+ }
18
+ async ensureLabel(name, color) {
19
+ try {
20
+ await this.glab(["label", "create", "--name", name, "--color", color]);
21
+ }
22
+ catch (err) {
23
+ const msg = err.message ?? "";
24
+ if (!msg.includes("already exists") && !msg.includes("409"))
25
+ throw err;
26
+ }
27
+ }
28
+ async ensureAllStateLabels() {
29
+ for (const label of STATE_LABELS)
30
+ await this.ensureLabel(label, LABEL_COLORS[label]);
31
+ }
32
+ async createIssue(title, description, label, assignees) {
33
+ const tempFile = join(tmpdir(), `devclaw-issue-${Date.now()}.md`);
34
+ await writeFile(tempFile, description, "utf-8");
35
+ try {
36
+ const { exec } = await import("node:child_process");
37
+ const execAsync = promisify(exec);
38
+ let cmd = `glab issue create --title "${title.replace(/"/g, '\\"')}" --description "$(cat ${tempFile})" --label "${label}"`;
39
+ if (assignees?.length)
40
+ cmd += ` --assignee "${assignees.join(",")}"`;
41
+ const { stdout } = await execAsync(cmd, { cwd: this.repoPath, timeout: 30_000 });
42
+ // glab issue create returns the issue URL
43
+ const match = stdout.trim().match(/\/issues\/(\d+)/);
44
+ if (!match)
45
+ throw new Error(`Failed to parse issue URL: ${stdout.trim()}`);
46
+ return this.getIssue(parseInt(match[1], 10));
47
+ }
48
+ finally {
49
+ try {
50
+ await unlink(tempFile);
51
+ }
52
+ catch { /* ignore */ }
53
+ }
54
+ }
55
+ async listIssuesByLabel(label) {
56
+ try {
57
+ const raw = await this.glab(["issue", "list", "--label", label, "--output", "json"]);
58
+ return JSON.parse(raw);
59
+ }
60
+ catch {
61
+ return [];
62
+ }
63
+ }
64
+ async getIssue(issueId) {
65
+ const raw = await this.glab(["issue", "view", String(issueId), "--output", "json"]);
66
+ return JSON.parse(raw);
67
+ }
68
+ async transitionLabel(issueId, from, to) {
69
+ const issue = await this.getIssue(issueId);
70
+ const stateLabels = issue.labels.filter((l) => STATE_LABELS.includes(l));
71
+ const args = ["issue", "update", String(issueId)];
72
+ for (const l of stateLabels)
73
+ args.push("--unlabel", l);
74
+ args.push("--label", to);
75
+ await this.glab(args);
76
+ }
77
+ async closeIssue(issueId) { await this.glab(["issue", "close", String(issueId)]); }
78
+ async reopenIssue(issueId) { await this.glab(["issue", "reopen", String(issueId)]); }
79
+ hasStateLabel(issue, expected) { return issue.labels.includes(expected); }
80
+ getCurrentStateLabel(issue) {
81
+ return STATE_LABELS.find((l) => issue.labels.includes(l)) ?? null;
82
+ }
83
+ async hasMergedMR(issueId) {
84
+ try {
85
+ const raw = await this.glab(["mr", "list", "--output", "json", "--state", "merged"]);
86
+ const mrs = JSON.parse(raw);
87
+ const pat = `#${issueId}`;
88
+ return mrs.some((mr) => mr.title.includes(pat) || (mr.description ?? "").includes(pat));
89
+ }
90
+ catch {
91
+ return false;
92
+ }
93
+ }
94
+ async getMergedMRUrl(issueId) {
95
+ try {
96
+ const raw = await this.glab(["mr", "list", "--output", "json", "--state", "merged"]);
97
+ const mrs = JSON.parse(raw);
98
+ const pat = `#${issueId}`;
99
+ const mr = mrs
100
+ .filter((mr) => mr.title.includes(pat) || (mr.description ?? "").includes(pat))
101
+ .sort((a, b) => new Date(b.merged_at).getTime() - new Date(a.merged_at).getTime())[0];
102
+ return mr?.web_url ?? null;
103
+ }
104
+ catch {
105
+ return null;
106
+ }
107
+ }
108
+ async addComment(issueId, body) {
109
+ const tempFile = join(tmpdir(), `devclaw-comment-${Date.now()}.md`);
110
+ await writeFile(tempFile, body, "utf-8");
111
+ try {
112
+ const { exec } = await import("node:child_process");
113
+ const execAsync = promisify(exec);
114
+ await execAsync(`glab issue note ${issueId} --message "$(cat ${tempFile})"`, { cwd: this.repoPath, timeout: 30_000 });
115
+ }
116
+ finally {
117
+ try {
118
+ await unlink(tempFile);
119
+ }
120
+ catch { /* ignore */ }
121
+ }
122
+ }
123
+ async healthCheck() {
124
+ try {
125
+ await this.glab(["auth", "status"]);
126
+ return true;
127
+ }
128
+ catch {
129
+ return false;
130
+ }
131
+ }
132
+ }
133
+ //# sourceMappingURL=gitlab.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitlab.js","sourceRoot":"","sources":["../../../lib/providers/gitlab.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { IssueProvider } from "./provider.js";
2
+ export type ProviderOptions = {
3
+ provider?: "gitlab" | "github";
4
+ repo?: string;
5
+ repoPath?: string;
6
+ };
7
+ export type ProviderWithType = {
8
+ provider: IssueProvider;
9
+ type: "github" | "gitlab";
10
+ };
11
+ export declare function createProvider(opts: ProviderOptions): ProviderWithType;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/providers/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAKnD,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAC3B,CAAC;AAWF,wBAAgB,cAAc,CAAC,IAAI,EAAE,eAAe,GAAG,gBAAgB,CAMtE"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Provider factory — auto-detects GitHub vs GitLab from git remote.
3
+ */
4
+ import { execFileSync } from "node:child_process";
5
+ import { GitLabProvider } from "./gitlab.js";
6
+ import { GitHubProvider } from "./github.js";
7
+ import { resolveRepoPath } from "../projects.js";
8
+ function detectProvider(repoPath) {
9
+ try {
10
+ const url = execFileSync("git", ["remote", "get-url", "origin"], { cwd: repoPath, timeout: 5_000 }).toString().trim();
11
+ return url.includes("github.com") ? "github" : "gitlab";
12
+ }
13
+ catch {
14
+ return "gitlab";
15
+ }
16
+ }
17
+ export function createProvider(opts) {
18
+ const repoPath = opts.repoPath ?? (opts.repo ? resolveRepoPath(opts.repo) : null);
19
+ if (!repoPath)
20
+ throw new Error("Either repoPath or repo must be provided");
21
+ const type = opts.provider ?? detectProvider(repoPath);
22
+ const provider = type === "github" ? new GitHubProvider({ repoPath }) : new GitLabProvider({ repoPath });
23
+ return { provider, type };
24
+ }
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/providers/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAajD,SAAS,cAAc,CAAC,QAAgB;IACtC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;QACtH,OAAO,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAqB;IAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAClF,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC3E,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,cAAc,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,cAAc,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;IACzG,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * IssueProvider — Abstract interface for issue tracker operations.
3
+ *
4
+ * Implementations: GitHub (gh CLI), GitLab (glab CLI).
5
+ */
6
+ export declare const STATE_LABELS: readonly ["Planning", "To Do", "Doing", "To Test", "Testing", "Done", "To Improve", "Refining"];
7
+ export type StateLabel = (typeof STATE_LABELS)[number];
8
+ export declare const LABEL_COLORS: Record<StateLabel, string>;
9
+ export type Issue = {
10
+ iid: number;
11
+ title: string;
12
+ description: string;
13
+ labels: string[];
14
+ state: string;
15
+ web_url: string;
16
+ };
17
+ export interface IssueProvider {
18
+ ensureLabel(name: string, color: string): Promise<void>;
19
+ ensureAllStateLabels(): Promise<void>;
20
+ createIssue(title: string, description: string, label: StateLabel, assignees?: string[]): Promise<Issue>;
21
+ listIssuesByLabel(label: StateLabel): Promise<Issue[]>;
22
+ getIssue(issueId: number): Promise<Issue>;
23
+ transitionLabel(issueId: number, from: StateLabel, to: StateLabel): Promise<void>;
24
+ closeIssue(issueId: number): Promise<void>;
25
+ reopenIssue(issueId: number): Promise<void>;
26
+ hasStateLabel(issue: Issue, expected: StateLabel): boolean;
27
+ getCurrentStateLabel(issue: Issue): StateLabel | null;
28
+ hasMergedMR(issueId: number): Promise<boolean>;
29
+ getMergedMRUrl(issueId: number): Promise<string | null>;
30
+ addComment(issueId: number, body: string): Promise<void>;
31
+ healthCheck(): Promise<boolean>;
32
+ }
33
+ /** @deprecated Use IssueProvider */
34
+ export type TaskManager = IssueProvider;
35
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../lib/providers/provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,YAAY,iGAEf,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAGnD,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACzG,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACvD,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1C,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClF,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC;IAC3D,oBAAoB,CAAC,KAAK,EAAE,KAAK,GAAG,UAAU,GAAG,IAAI,CAAC;IACtD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACxD,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CACjC;AAED,oCAAoC;AACpC,MAAM,MAAM,WAAW,GAAG,aAAa,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * IssueProvider — Abstract interface for issue tracker operations.
3
+ *
4
+ * Implementations: GitHub (gh CLI), GitLab (glab CLI).
5
+ */
6
+ export const STATE_LABELS = [
7
+ "Planning", "To Do", "Doing", "To Test", "Testing", "Done", "To Improve", "Refining",
8
+ ];
9
+ export const LABEL_COLORS = {
10
+ Planning: "#6699cc", "To Do": "#428bca", Doing: "#f0ad4e", "To Test": "#5bc0de",
11
+ Testing: "#9b59b6", Done: "#5cb85c", "To Improve": "#d9534f", Refining: "#f39c12",
12
+ };
13
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../../lib/providers/provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU;CAC5E,CAAC;AAIX,MAAM,CAAC,MAAM,YAAY,GAA+B;IACtD,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS;IAC/E,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS;CAClF,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Health service — worker health checks and auto-fix.
3
+ *
4
+ * Detects: active_no_session, zombie_session, stale_worker, inactive_with_issue.
5
+ * Used by both `status` (read-only) and `auto_pickup` (auto-fix).
6
+ */
7
+ import type { StateLabel } from "../providers/provider.js";
8
+ import { type Project } from "../projects.js";
9
+ export type HealthIssue = {
10
+ type: "active_no_session" | "zombie_session" | "stale_worker" | "inactive_with_issue";
11
+ severity: "critical" | "warning";
12
+ project: string;
13
+ groupId: string;
14
+ role: "dev" | "qa";
15
+ message: string;
16
+ level?: string | null;
17
+ sessionKey?: string | null;
18
+ hoursActive?: number;
19
+ issueId?: string | null;
20
+ };
21
+ export type HealthFix = {
22
+ issue: HealthIssue;
23
+ fixed: boolean;
24
+ labelReverted?: string;
25
+ labelRevertFailed?: boolean;
26
+ };
27
+ export declare function checkWorkerHealth(opts: {
28
+ workspaceDir: string;
29
+ groupId: string;
30
+ project: Project;
31
+ role: "dev" | "qa";
32
+ activeSessions: string[];
33
+ autoFix: boolean;
34
+ provider: {
35
+ transitionLabel(id: number, from: StateLabel, to: StateLabel): Promise<void>;
36
+ };
37
+ }): Promise<HealthFix[]>;
38
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../../lib/services/health.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAIL,KAAK,OAAO,EACb,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,mBAAmB,GAAG,gBAAgB,GAAG,cAAc,GAAG,qBAAqB,CAAC;IACtF,QAAQ,EAAE,UAAU,GAAG,SAAS,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,KAAK,GAAG,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,KAAK,GAAG,IAAI,CAAC;IACnB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE;QACR,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KAC9E,CAAC;CACH,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAqGvB"}
@@ -0,0 +1,100 @@
1
+ import { getSessionForLevel, getWorker, updateWorker, } from "../projects.js";
2
+ export async function checkWorkerHealth(opts) {
3
+ const { workspaceDir, groupId, project, role, activeSessions, autoFix, provider } = opts;
4
+ const fixes = [];
5
+ const worker = getWorker(project, role);
6
+ const sessionKey = worker.level ? getSessionForLevel(worker, worker.level) : null;
7
+ const revertLabel = role === "dev" ? "To Do" : "To Test";
8
+ const currentLabel = role === "dev" ? "Doing" : "Testing";
9
+ async function revertIssueLabel(fix) {
10
+ if (!worker.issueId)
11
+ return;
12
+ try {
13
+ const id = Number(worker.issueId.split(",")[0]);
14
+ await provider.transitionLabel(id, currentLabel, revertLabel);
15
+ fix.labelReverted = `${currentLabel} → ${revertLabel}`;
16
+ }
17
+ catch {
18
+ fix.labelRevertFailed = true;
19
+ }
20
+ }
21
+ // Check 1: Active but no session key for current level
22
+ if (worker.active && !sessionKey) {
23
+ const fix = {
24
+ issue: {
25
+ type: "active_no_session", severity: "critical",
26
+ project: project.name, groupId, role,
27
+ level: worker.level,
28
+ message: `${role.toUpperCase()} active but no session for level "${worker.level}"`,
29
+ },
30
+ fixed: false,
31
+ };
32
+ if (autoFix) {
33
+ await updateWorker(workspaceDir, groupId, role, { active: false, issueId: null, startTime: null });
34
+ fix.fixed = true;
35
+ }
36
+ fixes.push(fix);
37
+ }
38
+ // Check 2: Active with session but session is dead (zombie)
39
+ if (worker.active && sessionKey && activeSessions.length > 0 && !activeSessions.includes(sessionKey)) {
40
+ const fix = {
41
+ issue: {
42
+ type: "zombie_session", severity: "critical",
43
+ project: project.name, groupId, role,
44
+ sessionKey, level: worker.level,
45
+ message: `${role.toUpperCase()} session not in active sessions list`,
46
+ },
47
+ fixed: false,
48
+ };
49
+ if (autoFix) {
50
+ await revertIssueLabel(fix);
51
+ const sessions = { ...worker.sessions };
52
+ if (worker.level)
53
+ sessions[worker.level] = null;
54
+ await updateWorker(workspaceDir, groupId, role, { active: false, issueId: null, startTime: null, sessions });
55
+ fix.fixed = true;
56
+ }
57
+ fixes.push(fix);
58
+ }
59
+ // Check 3: Inactive but still has issueId
60
+ if (!worker.active && worker.issueId) {
61
+ const fix = {
62
+ issue: {
63
+ type: "inactive_with_issue", severity: "warning",
64
+ project: project.name, groupId, role,
65
+ issueId: worker.issueId,
66
+ message: `${role.toUpperCase()} inactive but still has issueId "${worker.issueId}"`,
67
+ },
68
+ fixed: false,
69
+ };
70
+ if (autoFix) {
71
+ await updateWorker(workspaceDir, groupId, role, { issueId: null });
72
+ fix.fixed = true;
73
+ }
74
+ fixes.push(fix);
75
+ }
76
+ // Check 4: Active for >2 hours (stale)
77
+ if (worker.active && worker.startTime && sessionKey) {
78
+ const hours = (Date.now() - new Date(worker.startTime).getTime()) / 3_600_000;
79
+ if (hours > 2) {
80
+ const fix = {
81
+ issue: {
82
+ type: "stale_worker", severity: "warning",
83
+ project: project.name, groupId, role,
84
+ hoursActive: Math.round(hours * 10) / 10,
85
+ sessionKey, issueId: worker.issueId,
86
+ message: `${role.toUpperCase()} active for ${Math.round(hours * 10) / 10}h — may need attention`,
87
+ },
88
+ fixed: false,
89
+ };
90
+ if (autoFix) {
91
+ await revertIssueLabel(fix);
92
+ await updateWorker(workspaceDir, groupId, role, { active: false, issueId: null, startTime: null });
93
+ fix.fixed = true;
94
+ }
95
+ fixes.push(fix);
96
+ }
97
+ }
98
+ return fixes;
99
+ }
100
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../../lib/services/health.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Heartbeat tick — token-free queue processing.
3
+ *
4
+ * Runs automatically via plugin service (periodic execution).
5
+ *
6
+ * Logic:
7
+ * 1. Health pass: auto-fix zombies, stale workers, orphaned state
8
+ * 2. Tick pass: fill free worker slots by priority
9
+ *
10
+ * Zero LLM tokens — all logic is deterministic code + CLI calls.
11
+ * Workers only consume tokens when they start processing dispatched tasks.
12
+ */
13
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
14
+ export type HeartbeatConfig = {
15
+ enabled: boolean;
16
+ intervalSeconds: number;
17
+ maxPickupsPerTick: number;
18
+ };
19
+ type TickResult = {
20
+ totalPickups: number;
21
+ totalHealthFixes: number;
22
+ totalSkipped: number;
23
+ };
24
+ export declare const HEARTBEAT_DEFAULTS: HeartbeatConfig;
25
+ export declare function resolveHeartbeatConfig(pluginConfig?: Record<string, unknown>): HeartbeatConfig;
26
+ export declare function registerHeartbeatService(api: OpenClawPluginApi): void;
27
+ export declare function tick(opts: {
28
+ workspaceDir: string;
29
+ agentId?: string;
30
+ config: HeartbeatConfig;
31
+ pluginConfig?: Record<string, unknown>;
32
+ logger: {
33
+ info(msg: string): void;
34
+ warn(msg: string): void;
35
+ };
36
+ }): Promise<TickResult>;
37
+ export {};
38
+ //# sourceMappingURL=heartbeat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat.d.ts","sourceRoot":"","sources":["../../../lib/services/heartbeat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAa7D,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAOF,KAAK,UAAU,GAAG;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAaF,eAAO,MAAM,kBAAkB,EAAE,eAIhC,CAAC;AAEF,wBAAgB,sBAAsB,CACpC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACrC,eAAe,CAGjB;AAMD,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,iBAAiB,QAuC9D;AAyFD,wBAAsB,IAAI,CAAC,IAAI,EAAE;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,eAAe,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,MAAM,EAAE;QAAE,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CAC9D,GAAG,OAAO,CAAC,UAAU,CAAC,CA+DtB"}