@desplega.ai/agent-swarm 1.102.0 → 1.103.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 (107) hide show
  1. package/dist/{actions-j9399ktm.js → actions-7txktrdj.js} +6 -6
  2. package/dist/{app-tnq1pz27.js → app-xm3xsdye.js} +3 -3
  3. package/dist/{assistant-c7y92gkw.js → assistant-qpv63wk6.js} +9 -9
  4. package/dist/{boot-reembed-k7e6fc1p.js → boot-reembed-9cxqka3e.js} +3 -3
  5. package/dist/{boot-reembed-b97r699t.js → boot-reembed-chxhrwv8.js} +4 -4
  6. package/dist/{boot-scrub-logs-14kbc61y.js → boot-scrub-logs-8qtfkcz8.js} +2 -2
  7. package/dist/{claude-managed-adapter-g07dbz3b.js → claude-managed-adapter-z29hjgzz.js} +3 -3
  8. package/dist/{cli-tsz1q7gk.js → cli-2307phk1.js} +375 -23
  9. package/dist/{cli-g5px3d7x.js → cli-2957pqpj.js} +24 -1
  10. package/dist/{cli-9qascwj7.js → cli-2qynerth.js} +1 -1
  11. package/dist/{cli-k1ghyj8b.js → cli-4fnp2tc3.js} +1 -1
  12. package/dist/{cli-hc4rd6sv.js → cli-85pf4z38.js} +1 -1
  13. package/dist/{cli-zk4gn40w.js → cli-8hyv6c2v.js} +6 -14
  14. package/dist/{cli-k81y1cjb.js → cli-8w95v19d.js} +1 -1
  15. package/dist/{cli-7xdq3jg3.js → cli-92fqyjcv.js} +1 -1
  16. package/dist/{cli-zctkpdmd.js → cli-dz3d6zjg.js} +1 -1
  17. package/dist/{cli-d0t4854c.js → cli-fedn86nz.js} +213 -476
  18. package/dist/{cli-g861fwjp.js → cli-fwxdt7kt.js} +3 -3
  19. package/dist/{cli-2aaa9mqr.js → cli-fygaw191.js} +2 -2
  20. package/dist/{cli-qbc6mncp.js → cli-gzepjz54.js} +2 -2
  21. package/dist/{cli-r68m8arr.js → cli-jt9d9fjw.js} +1 -1
  22. package/dist/{cli-axtg1zaa.js → cli-khe4x17a.js} +1 -1
  23. package/dist/{cli-sygq3fhn.js → cli-kk51f3tf.js} +5 -5
  24. package/dist/{cli-dgab5x2h.js → cli-krvxq8bc.js} +1 -1
  25. package/dist/{cli-xde8vhhp.js → cli-ksq38x4n.js} +2 -2
  26. package/dist/{cli-stqqf5kh.js → cli-m8f6qzck.js} +1 -1
  27. package/dist/{cli-ap4md0gc.js → cli-ns0r7mkr.js} +30 -5
  28. package/dist/{cli-t2jk33ta.js → cli-rttgde5f.js} +18 -6
  29. package/dist/{cli-mhj07xbq.js → cli-rvae030h.js} +3 -3
  30. package/dist/{cli-q6jzg6wj.js → cli-s14sb64w.js} +4 -4
  31. package/dist/{cli-zmf7refz.js → cli-v9283nma.js} +1 -1
  32. package/dist/{cli-fjx4x7nn.js → cli-xmtsan9k.js} +1 -1
  33. package/dist/{cli-vgck9mqq.js → cli-yeemwevj.js} +155 -37
  34. package/dist/{cli-5bqa41fd.js → cli-yfwwjeft.js} +1 -1
  35. package/dist/{cli-s8jw5bmg.js → cli-yp2krx5r.js} +2 -2
  36. package/dist/cli.js +9 -9
  37. package/dist/{codex-adapter-wf119mnw.js → codex-adapter-w0xharsg.js} +3 -3
  38. package/dist/{codex-session-runner-1gknw7mh.js → codex-session-runner-kzbjcm2k.js} +3 -3
  39. package/dist/{commands-2wyn3swb.js → commands-aqn63mcw.js} +2 -2
  40. package/dist/{db-567ntpxv.js → db-azrvwsnj.js} +2 -2
  41. package/dist/{handlers-wvwpk2kj.js → handlers-hf61har3.js} +9 -9
  42. package/dist/{hook-fatkywc0.js → hook-306p3yz4.js} +2 -2
  43. package/dist/{http-eq6wxve6.js → http-zts4haq7.js} +81 -62
  44. package/dist/{index-400x6p3j.js → index-29vg51x6.js} +6 -6
  45. package/dist/{index-9wqh5352.js → index-3c651yfk.js} +10 -10
  46. package/dist/{index-6aj8966p.js → index-bfh9hgek.js} +5 -5
  47. package/dist/{index-d1rm4ea3.js → index-h2yqjyk0.js} +8 -8
  48. package/dist/{keepalive-6x9nx92g.js → keepalive-a0dg5pds.js} +4 -4
  49. package/dist/{lead-5fgqwe13.js → lead-7mcxedkc.js} +21 -21
  50. package/dist/{maintenance-eajx5k1k.js → maintenance-mrzqd53t.js} +4 -4
  51. package/dist/{onboard-jc1w1edg.js → onboard-4dkpv9wa.js} +2 -2
  52. package/dist/{otel-impl-8k375amf.js → otel-impl-jt7gpyp9.js} +1 -1
  53. package/dist/{pi-mono-adapter-hf8sw7hs.js → pi-mono-adapter-zf7dt1wg.js} +1 -1
  54. package/dist/{pricing-refresh-zed6916t.js → pricing-refresh-xqnzh8dt.js} +4 -4
  55. package/dist/{seed-pricing-5805qzkz.js → seed-pricing-56tjm1fj.js} +3 -3
  56. package/dist/{setup-wz05vxh0.js → setup-tbwk8j10.js} +2 -2
  57. package/dist/{worker-j359graf.js → worker-e03za92t.js} +21 -21
  58. package/openapi.json +70 -1
  59. package/package.json +1 -1
  60. package/src/be/db.ts +83 -13
  61. package/src/be/migrations/098_repo_hooks_config.sql +3 -0
  62. package/src/be/task-lifecycle-events.ts +42 -0
  63. package/src/commands/runner.ts +174 -25
  64. package/src/github/task-reactions.ts +21 -0
  65. package/src/hooks/tool-loop-detection.test.ts +40 -0
  66. package/src/hooks/tool-loop-detection.ts +37 -1
  67. package/src/http/agents.ts +7 -0
  68. package/src/http/index.ts +16 -2
  69. package/src/http/prompt-templates.ts +1 -1
  70. package/src/http/repos.ts +5 -1
  71. package/src/http/schedules.ts +1 -1
  72. package/src/http/session-data.ts +2 -0
  73. package/src/http/tasks.ts +2 -1
  74. package/src/http/workflows.ts +1 -0
  75. package/src/prompts/resolver.ts +1 -1
  76. package/src/scheduler/scheduler.ts +25 -2
  77. package/src/server-runtime-counters.ts +12 -0
  78. package/src/server-user.ts +1 -2
  79. package/src/server.ts +5 -0
  80. package/src/telemetry.ts +18 -1
  81. package/src/tests/http-api-integration.test.ts +4 -0
  82. package/src/tests/model-control.test.ts +6 -6
  83. package/src/tests/swarm-repos.test.ts +25 -2
  84. package/src/tests/task-lifecycle-events.test.ts +53 -0
  85. package/src/tests/task-lifecycle-telemetry.test.ts +37 -1
  86. package/src/tests/telemetry-init.test.ts +32 -0
  87. package/src/tools/prompt-templates/preview.ts +1 -1
  88. package/src/tools/repos/update-repo.ts +6 -1
  89. package/src/tools/schedules/create-schedule.ts +1 -1
  90. package/src/tools/schedules/update-schedule.ts +1 -1
  91. package/src/tools/send-task.ts +7 -2
  92. package/src/tools/task-action.ts +6 -2
  93. package/src/types.ts +155 -1
  94. package/src/utils/template.ts +127 -0
  95. package/src/workflows/engine.ts +7 -0
  96. package/src/workflows/executors/agent-task.ts +1 -2
  97. package/src/workflows/template.ts +12 -121
  98. package/src/workflows/triggers.ts +6 -2
  99. package/templates/community/code-health-reports/PLAYBOOK.md +355 -0
  100. package/templates/community/code-health-reports/README.md +38 -0
  101. package/templates/community/code-health-reports/lead-prompt.md +52 -0
  102. package/templates/community/code-health-reports/report.mjs +378 -0
  103. package/templates/community/code-health-reports/run.sh +143 -0
  104. package/templates/schedules/weekly-code-health-reports/config.json +13 -0
  105. package/templates/schedules/weekly-code-health-reports/content.md +60 -0
  106. package/src/model-tiers.ts +0 -140
  107. package/templates/community/.gitkeep +0 -0
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  runAgent
3
- } from "./cli-vgck9mqq.js";
3
+ } from "./cli-yeemwevj.js";
4
4
  import"./cli-wjyyv518.js";
5
- import"./cli-axtg1zaa.js";
5
+ import"./cli-khe4x17a.js";
6
6
  import"./cli-p03mawph.js";
7
7
  import"./cli-4wmnp8q3.js";
8
- import"./cli-s8jw5bmg.js";
9
- import"./cli-7xdq3jg3.js";
10
- import"./cli-g5px3d7x.js";
8
+ import"./cli-yp2krx5r.js";
9
+ import"./cli-92fqyjcv.js";
10
+ import"./cli-2957pqpj.js";
11
11
  import"./cli-tyfxrrdd.js";
12
12
  import"./cli-ncg70f07.js";
13
13
  import"./cli-yazx6hap.js";
@@ -16,7 +16,7 @@ import"./cli-d6n0thxw.js";
16
16
  import"./cli-hx1dcevq.js";
17
17
  import {
18
18
  getEnabledCapabilities
19
- } from "./cli-tsz1q7gk.js";
19
+ } from "./cli-2307phk1.js";
20
20
  import"./cli-09rxrad0.js";
21
21
  import"./cli-dcfyyh3t.js";
22
22
  import"./cli-gz9sbyk3.js";
@@ -25,31 +25,31 @@ import"./cli-psrqtw2m.js";
25
25
  import"./cli-tng3131n.js";
26
26
  import"./cli-zm7njwzd.js";
27
27
  import"./cli-0k9dc6ks.js";
28
- import"./cli-zmf7refz.js";
29
- import"./cli-xde8vhhp.js";
30
- import"./cli-stqqf5kh.js";
31
- import"./cli-k1ghyj8b.js";
32
- import"./cli-zk4gn40w.js";
28
+ import"./cli-v9283nma.js";
29
+ import"./cli-ksq38x4n.js";
30
+ import"./cli-m8f6qzck.js";
31
+ import"./cli-4fnp2tc3.js";
32
+ import"./cli-8hyv6c2v.js";
33
33
  import"./cli-f14fvzag.js";
34
- import"./cli-qbc6mncp.js";
35
- import"./cli-2aaa9mqr.js";
36
- import"./cli-k81y1cjb.js";
34
+ import"./cli-gzepjz54.js";
35
+ import"./cli-fygaw191.js";
36
+ import"./cli-8w95v19d.js";
37
37
  import"./cli-fad8m16k.js";
38
- import"./cli-ap4md0gc.js";
39
- import"./cli-t2jk33ta.js";
38
+ import"./cli-ns0r7mkr.js";
39
+ import"./cli-rttgde5f.js";
40
40
  import"./cli-2deg0cen.js";
41
- import"./cli-sygq3fhn.js";
41
+ import"./cli-kk51f3tf.js";
42
42
  import"./cli-fete3y1e.js";
43
43
  import"./cli-b0p7rfnd.js";
44
- import"./cli-5bqa41fd.js";
44
+ import"./cli-yfwwjeft.js";
45
45
  import"./cli-z92pkwzn.js";
46
46
  import"./cli-dh55d5fg.js";
47
- import"./cli-r68m8arr.js";
48
- import"./cli-d0t4854c.js";
47
+ import"./cli-jt9d9fjw.js";
48
+ import"./cli-fedn86nz.js";
49
49
  import"./cli-z2zcxes1.js";
50
50
  import"./cli-q21d49ac.js";
51
51
  import"./cli-anrj584m.js";
52
- import"./cli-hc4rd6sv.js";
52
+ import"./cli-85pf4z38.js";
53
53
  import"./cli-3pp1362w.js";
54
54
  import"./cli-e15jhafb.js";
55
55
  import"./cli-9aryf9tv.js";
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  reembedAllScripts
3
- } from "./cli-2aaa9mqr.js";
4
- import"./cli-k81y1cjb.js";
5
- import"./cli-d0t4854c.js";
3
+ } from "./cli-fygaw191.js";
4
+ import"./cli-8w95v19d.js";
5
+ import"./cli-fedn86nz.js";
6
6
  import"./cli-z2zcxes1.js";
7
7
  import"./cli-q21d49ac.js";
8
8
  import"./cli-anrj584m.js";
9
- import"./cli-hc4rd6sv.js";
9
+ import"./cli-85pf4z38.js";
10
10
  import"./cli-3pp1362w.js";
11
11
  import"./cli-p9swy5t3.js";
12
12
 
@@ -3,7 +3,7 @@ import {
3
3
  createDefaultMcpJson,
4
4
  createDefaultSettingsLocal,
5
5
  createHooksConfig
6
- } from "./cli-fjx4x7nn.js";
6
+ } from "./cli-xmtsan9k.js";
7
7
  import {
8
8
  require_jsx_dev_runtime
9
9
  } from "./cli-6n1nnzm7.js";
@@ -13,7 +13,7 @@ import {
13
13
  import {
14
14
  init_package,
15
15
  package_default
16
- } from "./cli-hc4rd6sv.js";
16
+ } from "./cli-85pf4z38.js";
17
17
  import {
18
18
  Box_default,
19
19
  Select,
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  init_package,
8
8
  package_default
9
- } from "./cli-hc4rd6sv.js";
9
+ } from "./cli-85pf4z38.js";
10
10
  import {
11
11
  init_secret_scrubber,
12
12
  scrubSecrets
@@ -29,7 +29,7 @@ import"./cli-4wmnp8q3.js";
29
29
  import {
30
30
  checkToolLoop,
31
31
  clearToolHistory
32
- } from "./cli-g5px3d7x.js";
32
+ } from "./cli-2957pqpj.js";
33
33
  import {
34
34
  require_cross_spawn
35
35
  } from "./cli-yazx6hap.js";
@@ -2,13 +2,13 @@ import {
2
2
  PRICING_REFRESH_INTERVAL_MS,
3
3
  refreshPricingFromModelsDev,
4
4
  startPricingRefreshLoop
5
- } from "./cli-xde8vhhp.js";
6
- import"./cli-stqqf5kh.js";
7
- import"./cli-d0t4854c.js";
5
+ } from "./cli-ksq38x4n.js";
6
+ import"./cli-m8f6qzck.js";
7
+ import"./cli-fedn86nz.js";
8
8
  import"./cli-z2zcxes1.js";
9
9
  import"./cli-q21d49ac.js";
10
10
  import"./cli-anrj584m.js";
11
- import"./cli-hc4rd6sv.js";
11
+ import"./cli-85pf4z38.js";
12
12
  import"./cli-3pp1362w.js";
13
13
  import"./cli-p9swy5t3.js";
14
14
  export {
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  buildModelsDevSeedRows,
3
3
  seedPricingFromModelsDev
4
- } from "./cli-stqqf5kh.js";
5
- import"./cli-d0t4854c.js";
4
+ } from "./cli-m8f6qzck.js";
5
+ import"./cli-fedn86nz.js";
6
6
  import"./cli-z2zcxes1.js";
7
7
  import"./cli-q21d49ac.js";
8
8
  import"./cli-anrj584m.js";
9
- import"./cli-hc4rd6sv.js";
9
+ import"./cli-85pf4z38.js";
10
10
  import"./cli-3pp1362w.js";
11
11
  import"./cli-p9swy5t3.js";
12
12
  export {
@@ -4,14 +4,14 @@ import {
4
4
  createDefaultMcpJson,
5
5
  createDefaultSettingsLocal,
6
6
  createHooksConfig
7
- } from "./cli-fjx4x7nn.js";
7
+ } from "./cli-xmtsan9k.js";
8
8
  import {
9
9
  require_jsx_dev_runtime
10
10
  } from "./cli-6n1nnzm7.js";
11
11
  import {
12
12
  getApiKey
13
13
  } from "./cli-f14fvzag.js";
14
- import"./cli-hc4rd6sv.js";
14
+ import"./cli-85pf4z38.js";
15
15
  import {
16
16
  Box_default,
17
17
  Spinner,
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  runAgent
3
- } from "./cli-vgck9mqq.js";
3
+ } from "./cli-yeemwevj.js";
4
4
  import"./cli-wjyyv518.js";
5
- import"./cli-axtg1zaa.js";
5
+ import"./cli-khe4x17a.js";
6
6
  import"./cli-p03mawph.js";
7
7
  import"./cli-4wmnp8q3.js";
8
- import"./cli-s8jw5bmg.js";
9
- import"./cli-7xdq3jg3.js";
10
- import"./cli-g5px3d7x.js";
8
+ import"./cli-yp2krx5r.js";
9
+ import"./cli-92fqyjcv.js";
10
+ import"./cli-2957pqpj.js";
11
11
  import"./cli-tyfxrrdd.js";
12
12
  import"./cli-ncg70f07.js";
13
13
  import"./cli-yazx6hap.js";
@@ -16,7 +16,7 @@ import"./cli-d6n0thxw.js";
16
16
  import"./cli-hx1dcevq.js";
17
17
  import {
18
18
  getEnabledCapabilities
19
- } from "./cli-tsz1q7gk.js";
19
+ } from "./cli-2307phk1.js";
20
20
  import"./cli-09rxrad0.js";
21
21
  import"./cli-dcfyyh3t.js";
22
22
  import"./cli-gz9sbyk3.js";
@@ -25,31 +25,31 @@ import"./cli-psrqtw2m.js";
25
25
  import"./cli-tng3131n.js";
26
26
  import"./cli-zm7njwzd.js";
27
27
  import"./cli-0k9dc6ks.js";
28
- import"./cli-zmf7refz.js";
29
- import"./cli-xde8vhhp.js";
30
- import"./cli-stqqf5kh.js";
31
- import"./cli-k1ghyj8b.js";
32
- import"./cli-zk4gn40w.js";
28
+ import"./cli-v9283nma.js";
29
+ import"./cli-ksq38x4n.js";
30
+ import"./cli-m8f6qzck.js";
31
+ import"./cli-4fnp2tc3.js";
32
+ import"./cli-8hyv6c2v.js";
33
33
  import"./cli-f14fvzag.js";
34
- import"./cli-qbc6mncp.js";
35
- import"./cli-2aaa9mqr.js";
36
- import"./cli-k81y1cjb.js";
34
+ import"./cli-gzepjz54.js";
35
+ import"./cli-fygaw191.js";
36
+ import"./cli-8w95v19d.js";
37
37
  import"./cli-fad8m16k.js";
38
- import"./cli-ap4md0gc.js";
39
- import"./cli-t2jk33ta.js";
38
+ import"./cli-ns0r7mkr.js";
39
+ import"./cli-rttgde5f.js";
40
40
  import"./cli-2deg0cen.js";
41
- import"./cli-sygq3fhn.js";
41
+ import"./cli-kk51f3tf.js";
42
42
  import"./cli-fete3y1e.js";
43
43
  import"./cli-b0p7rfnd.js";
44
- import"./cli-5bqa41fd.js";
44
+ import"./cli-yfwwjeft.js";
45
45
  import"./cli-z92pkwzn.js";
46
46
  import"./cli-dh55d5fg.js";
47
- import"./cli-r68m8arr.js";
48
- import"./cli-d0t4854c.js";
47
+ import"./cli-jt9d9fjw.js";
48
+ import"./cli-fedn86nz.js";
49
49
  import"./cli-z2zcxes1.js";
50
50
  import"./cli-q21d49ac.js";
51
51
  import"./cli-anrj584m.js";
52
- import"./cli-hc4rd6sv.js";
52
+ import"./cli-85pf4z38.js";
53
53
  import"./cli-3pp1362w.js";
54
54
  import"./cli-e15jhafb.js";
55
55
  import"./cli-9aryf9tv.js";
package/openapi.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Agent Swarm API",
5
- "version": "1.102.0",
5
+ "version": "1.103.0",
6
6
  "description": "Multi-agent orchestration API for Claude Code, Codex, and Gemini CLI. Enables task distribution, agent communication, and service discovery.\n\nMCP tools are documented separately in [MCP.md](./MCP.md)."
7
7
  },
8
8
  "servers": [
@@ -6311,6 +6311,18 @@
6311
6311
  "type": "boolean",
6312
6312
  "default": true
6313
6313
  },
6314
+ "hooks": {
6315
+ "type": "object",
6316
+ "properties": {
6317
+ "enabled": {
6318
+ "type": "boolean",
6319
+ "default": false
6320
+ }
6321
+ },
6322
+ "default": {
6323
+ "enabled": false
6324
+ }
6325
+ },
6314
6326
  "guidelines": {
6315
6327
  "type": [
6316
6328
  "object",
@@ -6427,6 +6439,18 @@
6427
6439
  "autoClone": {
6428
6440
  "type": "boolean"
6429
6441
  },
6442
+ "hooks": {
6443
+ "type": [
6444
+ "object",
6445
+ "null"
6446
+ ],
6447
+ "properties": {
6448
+ "enabled": {
6449
+ "type": "boolean",
6450
+ "default": false
6451
+ }
6452
+ }
6453
+ },
6430
6454
  "guidelines": {
6431
6455
  "type": [
6432
6456
  "object",
@@ -6500,6 +6524,18 @@
6500
6524
  "type": "boolean",
6501
6525
  "default": true
6502
6526
  },
6527
+ "hooks": {
6528
+ "type": "object",
6529
+ "properties": {
6530
+ "enabled": {
6531
+ "type": "boolean",
6532
+ "default": false
6533
+ }
6534
+ },
6535
+ "default": {
6536
+ "enabled": false
6537
+ }
6538
+ },
6503
6539
  "guidelines": {
6504
6540
  "type": [
6505
6541
  "object",
@@ -6724,6 +6760,18 @@
6724
6760
  "type": "boolean",
6725
6761
  "default": true
6726
6762
  },
6763
+ "hooks": {
6764
+ "type": "object",
6765
+ "properties": {
6766
+ "enabled": {
6767
+ "type": "boolean",
6768
+ "default": false
6769
+ }
6770
+ },
6771
+ "default": {
6772
+ "enabled": false
6773
+ }
6774
+ },
6727
6775
  "guidelines": {
6728
6776
  "type": [
6729
6777
  "object",
@@ -6819,6 +6867,15 @@
6819
6867
  "autoClone": {
6820
6868
  "type": "boolean"
6821
6869
  },
6870
+ "hooks": {
6871
+ "type": "object",
6872
+ "properties": {
6873
+ "enabled": {
6874
+ "type": "boolean",
6875
+ "default": false
6876
+ }
6877
+ }
6878
+ },
6822
6879
  "guidelines": {
6823
6880
  "type": [
6824
6881
  "object",
@@ -6896,6 +6953,18 @@
6896
6953
  "type": "boolean",
6897
6954
  "default": true
6898
6955
  },
6956
+ "hooks": {
6957
+ "type": "object",
6958
+ "properties": {
6959
+ "enabled": {
6960
+ "type": "boolean",
6961
+ "default": false
6962
+ }
6963
+ },
6964
+ "default": {
6965
+ "enabled": false
6966
+ }
6967
+ },
6899
6968
  "guidelines": {
6900
6969
  "type": [
6901
6970
  "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@desplega.ai/agent-swarm",
3
- "version": "1.102.0",
3
+ "version": "1.103.0",
4
4
  "description": "Multi-agent orchestration for Claude Code, Codex, Gemini CLI, and other AI coding assistants",
5
5
  "license": "MIT",
6
6
  "author": "desplega.sh <contact@desplega.sh>",
package/src/be/db.ts CHANGED
@@ -1,8 +1,6 @@
1
1
  import { Database } from "bun:sqlite";
2
2
  import { parseProviderMeta } from "@/utils/provider-metadata.ts";
3
3
  import pkg from "../../package.json";
4
- import { addEyesReactionOnTaskStart } from "../github/task-reactions";
5
- import { type ModelTier, parseModelTier } from "../model-tiers";
6
4
  import { configureDbResolver } from "../prompts/resolver";
7
5
  import { telemetry } from "../telemetry";
8
6
  import type {
@@ -101,7 +99,12 @@ import type {
101
99
  WorkflowSummary,
102
100
  WorkflowVersion,
103
101
  } from "../types";
104
- import { FollowUpConfigSchema, isTerminalTaskStatus } from "../types";
102
+ import {
103
+ FollowUpConfigSchema,
104
+ isTerminalTaskStatus,
105
+ type ModelTier,
106
+ parseModelTier,
107
+ } from "../types";
105
108
  import { deriveProviderFromKeyType } from "../utils/credentials";
106
109
  import type { RateLimitWindowTelemetry } from "../utils/error-tracker";
107
110
  import { getCurrentRequestUserId } from "../utils/request-auth-context";
@@ -111,11 +114,17 @@ import { normalizeDate, normalizeDateRequired } from "./date-utils";
111
114
  import { runMigrations } from "./migrations/runner";
112
115
  import { seedDefaultTemplates } from "./seed-prompt-templates";
113
116
  import { isReservedConfigKey, reservedKeyError } from "./swarm-config-guard";
117
+ import { emitTaskStarted } from "./task-lifecycle-events";
114
118
 
115
119
  let db: Database | null = null;
116
120
  let sqliteVecAvailable = false;
117
121
 
118
122
  type TaskTelemetryProps = Parameters<typeof telemetry.taskEvent>[1];
123
+ type TaskTelemetryContext = {
124
+ provider?: ProviderName;
125
+ harnessVariant?: string;
126
+ harnessVersion?: string;
127
+ };
119
128
 
120
129
  function emitTaskLifecycleTelemetryAfterCommit(
121
130
  event: string,
@@ -128,6 +137,17 @@ function emitTaskLifecycleTelemetryAfterCommit(
128
137
  });
129
138
  }
130
139
 
140
+ function taskContextForTelemetry(task: AgentTask): TaskTelemetryContext {
141
+ const harnessVersion = task.harnessVariantMeta?.version;
142
+ const context: TaskTelemetryContext = {};
143
+ if (task.provider) context.provider = task.provider;
144
+ if (task.harnessVariant) context.harnessVariant = task.harnessVariant;
145
+ if (typeof harnessVersion === "string" || typeof harnessVersion === "number") {
146
+ context.harnessVersion = String(harnessVersion);
147
+ }
148
+ return context;
149
+ }
150
+
131
151
  export function isSqliteVecAvailable(): boolean {
132
152
  return sqliteVecAvailable;
133
153
  }
@@ -1375,9 +1395,9 @@ export function startTask(taskId: string): AgentTask | null {
1375
1395
  } catch {}
1376
1396
  }
1377
1397
  const result = row ? rowToAgentTask(row) : null;
1378
- // Fire-and-forget: add eyes reaction for GitHub-sourced tasks
1398
+ // Fire-and-forget: notify lifecycle subscribers (e.g. GitHub eyes reaction)
1379
1399
  if (result && oldTask.status !== "in_progress") {
1380
- addEyesReactionOnTaskStart(result).catch(() => {});
1400
+ emitTaskStarted(result);
1381
1401
  }
1382
1402
  return result;
1383
1403
  }
@@ -2153,6 +2173,8 @@ export function completeTask(id: string, output?: string): AgentTask | null {
2153
2173
  "completed",
2154
2174
  {
2155
2175
  taskId: id,
2176
+ source: oldTask.source,
2177
+ ...taskContextForTelemetry(oldTask),
2156
2178
  agentId: row.agentId ?? undefined,
2157
2179
  durationMs: row.createdAt ? Date.now() - new Date(row.createdAt).getTime() : undefined,
2158
2180
  },
@@ -2203,6 +2225,8 @@ export function failTask(id: string, reason: string): AgentTask | null {
2203
2225
  "failed",
2204
2226
  {
2205
2227
  taskId: id,
2228
+ source: oldTask.source,
2229
+ ...taskContextForTelemetry(oldTask),
2206
2230
  agentId: row.agentId ?? undefined,
2207
2231
  durationMs: row.createdAt ? Date.now() - new Date(row.createdAt).getTime() : undefined,
2208
2232
  },
@@ -2337,6 +2361,21 @@ export function supersedeTask(
2337
2361
  .get(finishedAt, id);
2338
2362
 
2339
2363
  if (row && oldTask) {
2364
+ emitTaskLifecycleTelemetryAfterCommit(
2365
+ "superseded",
2366
+ {
2367
+ taskId: id,
2368
+ source: oldTask.source,
2369
+ ...taskContextForTelemetry(oldTask),
2370
+ agentId: row.agentId ?? undefined,
2371
+ reason: args.reason,
2372
+ durationMs: oldTask.createdAt
2373
+ ? Date.now() - new Date(oldTask.createdAt).getTime()
2374
+ : undefined,
2375
+ },
2376
+ (task) => task?.status === "superseded",
2377
+ );
2378
+
2340
2379
  try {
2341
2380
  createLogEntry({
2342
2381
  eventType: "task_superseded",
@@ -3255,7 +3294,7 @@ export function createTaskExtended(task: string, options?: CreateTaskOptions): A
3255
3294
  {
3256
3295
  taskId: row.id,
3257
3296
  source: row.source,
3258
- tags: options?.tags ?? [],
3297
+ ...taskContextForTelemetry(rowToAgentTask(row)),
3259
3298
  hasParent: !!row.parentTaskId,
3260
3299
  priority: row.priority,
3261
3300
  },
@@ -3305,9 +3344,9 @@ export function claimTask(taskId: string, agentId: string): AgentTask | null {
3305
3344
  }
3306
3345
 
3307
3346
  const result = row ? rowToAgentTask(row) : null;
3308
- // Fire-and-forget: add eyes reaction for GitHub-sourced tasks
3347
+ // Fire-and-forget: notify lifecycle subscribers (e.g. GitHub eyes reaction)
3309
3348
  if (result) {
3310
- addEyesReactionOnTaskStart(result).catch(() => {});
3349
+ emitTaskStarted(result);
3311
3350
  }
3312
3351
  return result;
3313
3352
  }
@@ -6183,6 +6222,7 @@ type SwarmRepoRow = {
6183
6222
  clonePath: string;
6184
6223
  defaultBranch: string;
6185
6224
  autoClone: number; // SQLite boolean
6225
+ hooks: string | null;
6186
6226
  guidelines: string | null;
6187
6227
  createdAt: string;
6188
6228
  lastUpdatedAt: string;
@@ -6196,6 +6236,7 @@ function rowToSwarmRepo(row: SwarmRepoRow): SwarmRepo {
6196
6236
  clonePath: row.clonePath,
6197
6237
  defaultBranch: row.defaultBranch,
6198
6238
  autoClone: row.autoClone === 1,
6239
+ hooks: row.hooks ? JSON.parse(row.hooks) : { enabled: false },
6199
6240
  guidelines: row.guidelines ? JSON.parse(row.guidelines) : null,
6200
6241
  createdAt: row.createdAt,
6201
6242
  lastUpdatedAt: row.lastUpdatedAt,
@@ -6251,20 +6292,22 @@ export function createSwarmRepo(data: {
6251
6292
  clonePath?: string;
6252
6293
  defaultBranch?: string;
6253
6294
  autoClone?: boolean;
6295
+ hooks?: { enabled: boolean };
6254
6296
  guidelines?: RepoGuidelines | null;
6255
6297
  }): SwarmRepo {
6256
6298
  const id = crypto.randomUUID();
6257
6299
  const now = new Date().toISOString();
6258
- const clonePath = data.clonePath || `/workspace/repos/${data.name}`;
6300
+ const clonePath = data.clonePath || `/workspace/personal/repos/${data.name}`;
6301
+ const hooksJson = JSON.stringify(data.hooks ?? { enabled: true });
6259
6302
  const guidelinesJson = data.guidelines ? JSON.stringify(data.guidelines) : null;
6260
6303
 
6261
6304
  const row = getDb()
6262
6305
  .prepare<
6263
6306
  SwarmRepoRow,
6264
- [string, string, string, string, string, number, string | null, string, string]
6307
+ [string, string, string, string, string, number, string | null, string | null, string, string]
6265
6308
  >(
6266
- `INSERT INTO swarm_repos (id, url, name, clonePath, defaultBranch, autoClone, guidelines, createdAt, lastUpdatedAt)
6267
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`,
6309
+ `INSERT INTO swarm_repos (id, url, name, clonePath, defaultBranch, autoClone, hooks, guidelines, createdAt, lastUpdatedAt)
6310
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`,
6268
6311
  )
6269
6312
  .get(
6270
6313
  id,
@@ -6273,6 +6316,7 @@ export function createSwarmRepo(data: {
6273
6316
  clonePath,
6274
6317
  data.defaultBranch ?? "main",
6275
6318
  data.autoClone !== false ? 1 : 0,
6319
+ hooksJson,
6276
6320
  guidelinesJson,
6277
6321
  now,
6278
6322
  now,
@@ -6290,6 +6334,7 @@ export function updateSwarmRepo(
6290
6334
  clonePath: string;
6291
6335
  defaultBranch: string;
6292
6336
  autoClone: boolean;
6337
+ hooks: { enabled: boolean } | null;
6293
6338
  guidelines: RepoGuidelines | null;
6294
6339
  }>,
6295
6340
  ): SwarmRepo | null {
@@ -6307,6 +6352,10 @@ export function updateSwarmRepo(
6307
6352
  setClauses.push("autoClone = ?");
6308
6353
  params.push(updates.autoClone ? 1 : 0);
6309
6354
  }
6355
+ if (updates.hooks !== undefined) {
6356
+ setClauses.push("hooks = ?");
6357
+ params.push(updates.hooks ? JSON.stringify(updates.hooks) : null);
6358
+ }
6310
6359
  if (updates.guidelines !== undefined) {
6311
6360
  setClauses.push("guidelines = ?");
6312
6361
  params.push(updates.guidelines ? JSON.stringify(updates.guidelines) : null);
@@ -7037,6 +7086,22 @@ export function getWorkflowRun(id: string): WorkflowRun | null {
7037
7086
  return row ? rowToWorkflowRun(row) : null;
7038
7087
  }
7039
7088
 
7089
+ function emitWorkflowTerminalTelemetry(run: WorkflowRun): void {
7090
+ if (run.status !== "completed" && run.status !== "failed") return;
7091
+
7092
+ queueMicrotask(() => {
7093
+ const latest = getWorkflowRun(run.id);
7094
+ if (!latest || latest.status !== run.status) return;
7095
+ const steps = getWorkflowRunStepsByRunId(run.id);
7096
+ telemetry.workflow(run.status, {
7097
+ workflowId: run.workflowId,
7098
+ durationMs: run.startedAt ? Date.now() - new Date(run.startedAt).getTime() : undefined,
7099
+ stepsCompleted: steps.filter((step) => step.status === "completed").length,
7100
+ stepsFailed: steps.filter((step) => step.status === "failed").length,
7101
+ });
7102
+ });
7103
+ }
7104
+
7040
7105
  export function updateWorkflowRun(
7041
7106
  id: string,
7042
7107
  data: {
@@ -7073,7 +7138,12 @@ export function updateWorkflowRun(
7073
7138
  `UPDATE workflow_runs SET ${updates.join(", ")} WHERE id = ? RETURNING *`,
7074
7139
  )
7075
7140
  .get(...params);
7076
- return row ? rowToWorkflowRun(row) : null;
7141
+ if (!row) return null;
7142
+ const run = rowToWorkflowRun(row);
7143
+ if (data.status === "completed" || data.status === "failed") {
7144
+ emitWorkflowTerminalTelemetry(run);
7145
+ }
7146
+ return run;
7077
7147
  }
7078
7148
 
7079
7149
  export function listWorkflowRuns(workflowId: string): WorkflowRun[] {
@@ -0,0 +1,3 @@
1
+ -- Add opt-in hook installation config for worker repo setup.
2
+ -- Stores a JSON string of { enabled: boolean }. NULL means hooks are disabled.
3
+ ALTER TABLE swarm_repos ADD COLUMN hooks TEXT DEFAULT NULL;
@@ -0,0 +1,42 @@
1
+ import type { AgentTask } from "../types";
2
+
3
+ /**
4
+ * Minimal in-process task-lifecycle event emitter.
5
+ *
6
+ * This exists to invert a layering dependency: the data layer (`be/db`) used to
7
+ * import a GitHub integration (`github/task-reactions`) so it could add an 👀
8
+ * reaction when a task started. Instead, `be/db` now emits a `task-started`
9
+ * event and the GitHub integration subscribes at API-server boot. The data layer
10
+ * no longer depends on any integration.
11
+ *
12
+ * Handlers run synchronously in registration order. Each is wrapped in try/catch
13
+ * so a throwing handler never breaks task processing. Handlers may return a
14
+ * promise; it is ignored (fire-and-forget), but any async rejection is swallowed
15
+ * so it never surfaces as an unhandled rejection. This preserves the original
16
+ * `addEyesReactionOnTaskStart(result).catch(() => {})` semantics exactly.
17
+ */
18
+
19
+ type TaskStartedHandler = (task: AgentTask) => void | Promise<void>;
20
+
21
+ const taskStartedHandlers: TaskStartedHandler[] = [];
22
+
23
+ /** Register a handler invoked whenever a task transitions to `in_progress`. */
24
+ export function onTaskStarted(handler: TaskStartedHandler): void {
25
+ taskStartedHandlers.push(handler);
26
+ }
27
+
28
+ /** Emit the task-started event. Never throws. */
29
+ export function emitTaskStarted(task: AgentTask): void {
30
+ for (const handler of taskStartedHandlers) {
31
+ try {
32
+ const result = handler(task);
33
+ // Fire-and-forget: ignore the returned promise but swallow async
34
+ // rejections so a failing handler never crashes the process.
35
+ if (result && typeof (result as Promise<void>).catch === "function") {
36
+ (result as Promise<void>).catch(() => {});
37
+ }
38
+ } catch {
39
+ // A throwing handler must never break task processing.
40
+ }
41
+ }
42
+ }