@desplega.ai/agent-swarm 1.111.0 → 1.113.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 (156) hide show
  1. package/dist/{actions-a4crgvtd.js → actions-q4n7cz6e.js} +6 -6
  2. package/dist/{app-va5mr9yw.js → app-es4nzc71.js} +3 -3
  3. package/dist/{assistant-0jm4vy8r.js → assistant-0x8ey0vs.js} +9 -9
  4. package/dist/{boot-reembed-50zzk97q.js → boot-reembed-69agkhv6.js} +4 -4
  5. package/dist/{boot-reembed-0t815mmm.js → boot-reembed-p0ny05t8.js} +3 -3
  6. package/dist/{boot-scrub-logs-r99nbmxh.js → boot-scrub-logs-yybrkmvr.js} +2 -2
  7. package/dist/{cli-h3vhr1gj.js → cli-30bbaveh.js} +2 -2
  8. package/dist/{cli-ee3fkebs.js → cli-36ymmpmp.js} +2 -2
  9. package/dist/{cli-dza5039b.js → cli-4xyj9jtq.js} +1495 -254
  10. package/dist/{cli-3cm8ar1c.js → cli-bgef578c.js} +1 -1
  11. package/dist/{cli-xqzvygxp.js → cli-bgvskydy.js} +11 -2
  12. package/dist/{cli-t8m00q3b.js → cli-bnzbn8j8.js} +3 -3
  13. package/dist/{cli-kavm2cv5.js → cli-c3frqf65.js} +4 -3
  14. package/dist/{cli-2b0ew5v8.js → cli-c9mtm09b.js} +1 -1
  15. package/dist/{cli-0d5xddf1.js → cli-f3qa069v.js} +2 -2
  16. package/dist/{cli-r3y5chyg.js → cli-gtkqc144.js} +4 -4
  17. package/dist/{cli-0d404x64.js → cli-h3k622d0.js} +1 -1
  18. package/dist/{cli-y7v6e7yr.js → cli-hjhvekf4.js} +4 -4
  19. package/dist/{cli-fdnpymsv.js → cli-hsetkkd3.js} +4 -2
  20. package/dist/{cli-8j1h9627.js → cli-mq580e06.js} +61 -14
  21. package/dist/{cli-4ke1amr9.js → cli-ncfgsqbd.js} +63 -7
  22. package/dist/{cli-jrmjxsnk.js → cli-pwc5e83c.js} +3 -3
  23. package/dist/{cli-4f6vw5vy.js → cli-qwgtacd6.js} +2 -2
  24. package/dist/{cli-gchg43wt.js → cli-r5g6ngtn.js} +1 -1
  25. package/dist/{cli-6tfm5fr1.js → cli-tbw13sx8.js} +1 -1
  26. package/dist/{cli-f1f82qgv.js → cli-trmapn9k.js} +5 -5
  27. package/dist/{cli-aqr96mny.js → cli-y4ycrnjc.js} +1 -1
  28. package/dist/{cli-z626gjqj.js → cli-y6mrptcn.js} +1 -1
  29. package/dist/{cli-1aqc46he.js → cli-z46pnksz.js} +5 -5
  30. package/dist/cli.js +11 -10
  31. package/dist/{commands-t3rdvb55.js → commands-z5dbwta3.js} +2 -2
  32. package/dist/{db-mjqc8hj6.js → db-bbgahh4z.js} +2 -2
  33. package/dist/{handlers-mcmg5qgc.js → handlers-6b44317z.js} +9 -9
  34. package/dist/{hook-0p4q1tym.js → hook-sbp5fmps.js} +1 -1
  35. package/dist/{http-gs6fk9sg.js → http-2xz43gz3.js} +356 -94
  36. package/dist/{index-20mf9wvc.js → index-0gzmqj4k.js} +8 -8
  37. package/dist/{index-w15fk28m.js → index-5ghxn8s6.js} +7 -7
  38. package/dist/{index-744yvc8x.js → index-nhat35em.js} +9 -9
  39. package/dist/{index-6zpajd9e.js → index-vfedgdw6.js} +26 -15
  40. package/dist/{keepalive-3gvnbxaj.js → keepalive-62gfj91d.js} +4 -4
  41. package/dist/{lead-yjbmhj3g.js → lead-ag0akn0v.js} +17 -17
  42. package/dist/{maintenance-jbvy2bfg.js → maintenance-xxrrzk5x.js} +4 -4
  43. package/dist/{onboard-sexatejh.js → onboard-64zyfcbs.js} +2 -2
  44. package/dist/{otel-impl-sgqvcw0f.js → otel-impl-b86qseaa.js} +1 -1
  45. package/dist/{pricing-refresh-rat240yg.js → pricing-refresh-cgtkffpa.js} +4 -4
  46. package/dist/{seed-pricing-7yfaf123.js → seed-pricing-1r1y1xkq.js} +3 -3
  47. package/dist/{setup-vm5vcc6c.js → setup-mkcgkjf7.js} +2 -2
  48. package/dist/{worker-02y2r0r2.js → worker-351sze63.js} +17 -17
  49. package/openapi.json +314 -3
  50. package/package.json +4 -3
  51. package/src/be/db.ts +43 -3
  52. package/src/be/memory/providers/sqlite-store.ts +5 -1
  53. package/src/be/migrations/108_rbac_permission_audit.sql +26 -0
  54. package/src/be/rbac-audit.ts +218 -0
  55. package/src/be/scripts/typecheck.ts +2 -0
  56. package/src/commands/runner.ts +154 -8
  57. package/src/github/handlers.ts +128 -25
  58. package/src/http/all-routes.ts +58 -0
  59. package/src/http/config.ts +55 -0
  60. package/src/http/favorites.ts +5 -0
  61. package/src/http/fs.ts +27 -7
  62. package/src/http/index.ts +26 -0
  63. package/src/http/kv.ts +21 -4
  64. package/src/http/route-def.ts +9 -0
  65. package/src/http/schedules.ts +56 -22
  66. package/src/http/scripts.ts +33 -0
  67. package/src/http/workflows.ts +13 -2
  68. package/src/prompts/base-prompt.ts +7 -6
  69. package/src/prompts/session-templates.ts +38 -11
  70. package/src/rbac/can.ts +44 -0
  71. package/src/rbac/index.ts +13 -0
  72. package/src/rbac/legacy-policy.ts +185 -0
  73. package/src/rbac/permissions.ts +182 -0
  74. package/src/rbac/types.ts +45 -0
  75. package/src/scripts-runtime/sdk-allowlist.ts +3 -0
  76. package/src/scripts-runtime/swarm-sdk.ts +81 -0
  77. package/src/scripts-runtime/types/stdlib.d.ts +18 -2
  78. package/src/scripts-runtime/types/swarm-sdk.d.ts +20 -2
  79. package/src/server.ts +6 -0
  80. package/src/slack/message-text.ts +25 -0
  81. package/src/stdio.ts +43 -0
  82. package/src/tests/base-prompt.test.ts +7 -4
  83. package/src/tests/github-event-filter.test.ts +3 -2
  84. package/src/tests/github-handlers-inline-comments.test.ts +114 -24
  85. package/src/tests/harness-provider-resolution.test.ts +5 -0
  86. package/src/tests/http-api-integration.test.ts +8 -1
  87. package/src/tests/prompt-template-session.test.ts +21 -8
  88. package/src/tests/rbac-audit.test.ts +345 -0
  89. package/src/tests/rbac-charact-http.test.ts +272 -0
  90. package/src/tests/rbac-charact-misc-tools.test.ts +428 -0
  91. package/src/tests/rbac-charact-skills.test.ts +492 -0
  92. package/src/tests/rbac-charact-slack.test.ts +283 -0
  93. package/src/tests/rbac-e2e-helpers.ts +305 -0
  94. package/src/tests/rbac-engine.test.ts +433 -0
  95. package/src/tests/rbac-lifecycle-e2e.test.ts +262 -0
  96. package/src/tests/rbac-wire-e2e.test.ts +574 -0
  97. package/src/tests/runner-repo-autostash.test.ts +168 -1
  98. package/src/tests/schedule-http-triage-tools.test.ts +121 -0
  99. package/src/tests/scheduled-tasks.test.ts +34 -0
  100. package/src/tests/scripts-http.test.ts +56 -7
  101. package/src/tests/slack-delete.test.ts +157 -0
  102. package/src/tests/slack-message-text.test.ts +37 -1
  103. package/src/tests/slack-update.test.ts +167 -0
  104. package/src/tests/swarm-config-reserved-keys.test.ts +17 -0
  105. package/src/tests/tool-annotations.test.ts +4 -0
  106. package/src/tests/update-schedule-mcp-tool.test.ts +57 -0
  107. package/src/tests/workflow-http-v2.test.ts +80 -0
  108. package/src/tools/cancel-task.ts +13 -3
  109. package/src/tools/context-diff.ts +12 -1
  110. package/src/tools/context-history.ts +12 -1
  111. package/src/tools/credential-bindings/tool.ts +12 -1
  112. package/src/tools/delete-channel.ts +12 -1
  113. package/src/tools/get-task-details.ts +1 -1
  114. package/src/tools/inject-learning.ts +12 -1
  115. package/src/tools/kv/kv-delete.ts +3 -18
  116. package/src/tools/kv/kv-incr.ts +3 -18
  117. package/src/tools/kv/kv-set.ts +3 -20
  118. package/src/tools/kv/kv-write-auth.ts +40 -0
  119. package/src/tools/manage-user.ts +12 -1
  120. package/src/tools/mcp-servers/mcp-server-create.ts +12 -1
  121. package/src/tools/mcp-servers/mcp-server-delete.ts +12 -1
  122. package/src/tools/mcp-servers/mcp-server-install.ts +12 -1
  123. package/src/tools/mcp-servers/mcp-server-uninstall.ts +12 -1
  124. package/src/tools/mcp-servers/mcp-server-update.ts +12 -1
  125. package/src/tools/memory-delete.ts +12 -4
  126. package/src/tools/register-kapso-number.ts +23 -2
  127. package/src/tools/schedules/create-schedule.ts +4 -3
  128. package/src/tools/schedules/index.ts +1 -0
  129. package/src/tools/schedules/list-schedules.ts +36 -2
  130. package/src/tools/schedules/patch-schedule.ts +405 -0
  131. package/src/tools/schedules/update-schedule.ts +2 -2
  132. package/src/tools/script-connections/tool.ts +12 -1
  133. package/src/tools/skills/skill-create.ts +12 -1
  134. package/src/tools/skills/skill-delete.ts +12 -1
  135. package/src/tools/skills/skill-install-remote.ts +12 -1
  136. package/src/tools/skills/skill-install.ts +12 -1
  137. package/src/tools/skills/skill-uninstall.ts +12 -1
  138. package/src/tools/skills/skill-update.ts +25 -2
  139. package/src/tools/slack-delete.ts +109 -0
  140. package/src/tools/slack-post.ts +8 -1
  141. package/src/tools/slack-read.ts +8 -1
  142. package/src/tools/slack-reply.ts +11 -3
  143. package/src/tools/slack-start-thread.ts +10 -1
  144. package/src/tools/slack-update.ts +134 -0
  145. package/src/tools/slack-upload-file.ts +8 -1
  146. package/src/tools/swarm-config/delete-config.ts +28 -1
  147. package/src/tools/swarm-config/get-config.ts +32 -5
  148. package/src/tools/swarm-config/list-config.ts +31 -5
  149. package/src/tools/swarm-config/set-config.ts +38 -1
  150. package/src/tools/task-action.ts +1 -1
  151. package/src/tools/task-tool-ctx.ts +19 -3
  152. package/src/tools/tool-config.ts +5 -2
  153. package/src/tools/update-profile.ts +8 -1
  154. package/src/tools/workflows/list-workflows.ts +14 -2
  155. package/templates/skills/swarm-scripts/SKILL.md +4 -9
  156. package/templates/skills/swarm-scripts/content.md +20 -9
@@ -3,7 +3,7 @@ import {
3
3
  init_date_utils,
4
4
  init_db,
5
5
  normalizeDateRequired
6
- } from "./cli-4ke1amr9.js";
6
+ } from "./cli-ncfgsqbd.js";
7
7
 
8
8
  // src/be/db-queries/oauth.ts
9
9
  init_date_utils();
@@ -3,7 +3,7 @@ import {
3
3
  getAgentWorkingOnThread,
4
4
  getAllAgents,
5
5
  init_db
6
- } from "./cli-4ke1amr9.js";
6
+ } from "./cli-ncfgsqbd.js";
7
7
 
8
8
  // src/slack/router.ts
9
9
  init_db();
@@ -181,6 +181,15 @@ ${bodyText}` : topText;
181
181
  }
182
182
  return bodyText || topText;
183
183
  }
184
+ function parseSlackTs(input) {
185
+ const trimmed = input.trim();
186
+ if (/^\d{6,}\.\d{1,}$/.test(trimmed))
187
+ return trimmed;
188
+ const m = trimmed.match(/p?(\d{10})(\d{6})(?:\D|$)/);
189
+ if (m)
190
+ return `${m[1]}.${m[2]}`;
191
+ return trimmed;
192
+ }
184
193
 
185
194
  // src/tasks/additive-buffer.ts
186
195
  function createAdditiveBuffer(options) {
@@ -252,4 +261,4 @@ function createAdditiveBuffer(options) {
252
261
  };
253
262
  }
254
263
 
255
- export { hasOtherUserMention, routeMessage, extractTaskFromMessage, extractSlackMessageText, createAdditiveBuffer };
264
+ export { hasOtherUserMention, routeMessage, extractTaskFromMessage, extractSlackMessageText, parseSlackTs, createAdditiveBuffer };
@@ -4,11 +4,11 @@ import {
4
4
  getNextResumeGeneration,
5
5
  getResumeGeneration,
6
6
  repointTrackerSyncBySwarmId
7
- } from "./cli-gchg43wt.js";
7
+ } from "./cli-r5g6ngtn.js";
8
8
  import {
9
9
  getExecutorRegistry,
10
10
  recoverIncompleteRuns
11
- } from "./cli-1aqc46he.js";
11
+ } from "./cli-z46pnksz.js";
12
12
  import {
13
13
  MAX_EMPTY_POLLS,
14
14
  assignUnassignedTaskPending,
@@ -44,7 +44,7 @@ import {
44
44
  resolveTemplate,
45
45
  supersedeTask,
46
46
  updateAgentStatus
47
- } from "./cli-4ke1amr9.js";
47
+ } from "./cli-ncfgsqbd.js";
48
48
 
49
49
  // src/heartbeat/heartbeat.ts
50
50
  init_db();
@@ -7,7 +7,7 @@ var package_default;
7
7
  var init_package = __esm(() => {
8
8
  package_default = {
9
9
  name: "@desplega.ai/agent-swarm",
10
- version: "1.111.0",
10
+ version: "1.113.0",
11
11
  description: "Multi-agent orchestration for Claude Code, Codex, Gemini CLI, and other AI coding assistants",
12
12
  license: "MIT",
13
13
  author: "desplega.sh <contact@desplega.sh>",
@@ -75,6 +75,7 @@ var init_package = __esm(() => {
75
75
  "check:db-boundary": "bash scripts/check-db-boundary.sh",
76
76
  "check:dep-graph": "depcruise src plugin/opencode-plugins --config .dependency-cruiser.cjs",
77
77
  "check:api-key-boundary": "bash scripts/check-api-key-boundary.sh",
78
+ "check:rbac-coverage": "bun scripts/check-rbac-coverage.ts",
78
79
  "check:audit-columns": "bash scripts/check-audit-columns.sh",
79
80
  "lint:structure": "konsistent check",
80
81
  "prepare-release": "bun scripts/prepare-release.ts",
@@ -152,8 +153,8 @@ var init_package = __esm(() => {
152
153
  "@inkjs/ui": "^2.0.0",
153
154
  "@linear/sdk": "^77.0.0",
154
155
  "@modelcontextprotocol/sdk": "^1.25.1",
155
- "@openai/codex-sdk": "^0.142.5",
156
- "@opencode-ai/sdk": "^1.17.13",
156
+ "@openai/codex-sdk": "^0.143.0",
157
+ "@opencode-ai/sdk": "^1.17.15",
157
158
  "@openfort/openfort-node": "^0.9.1",
158
159
  "@opentelemetry/api": "^1.9.1",
159
160
  "@opentelemetry/exporter-metrics-otlp-http": "^0.218.0",
@@ -3,7 +3,7 @@ import {
3
3
  incrKv,
4
4
  init_db,
5
5
  upsertKv
6
- } from "./cli-4ke1amr9.js";
6
+ } from "./cli-ncfgsqbd.js";
7
7
 
8
8
  // src/be/unmapped-identities.ts
9
9
  init_db();
@@ -6,7 +6,7 @@ import {
6
6
  getDb,
7
7
  init_db,
8
8
  isSqliteVecAvailable
9
- } from "./cli-4ke1amr9.js";
9
+ } from "./cli-ncfgsqbd.js";
10
10
  import {
11
11
  __esm,
12
12
  __export,
@@ -6740,7 +6740,7 @@ class SqliteMemoryStore {
6740
6740
  }
6741
6741
  }
6742
6742
  deleteFtsRows(ids) {
6743
- if (ids.length === 0 || !this.ftsInitialized && !this.getFtsTableSchema())
6743
+ if (ids.length === 0 || !this.getFtsTableSchema())
6744
6744
  return;
6745
6745
  const db = getDb();
6746
6746
  const placeholders = ids.map(() => "?").join(",");
@@ -4,14 +4,14 @@ import {
4
4
  handleScheduleTrigger,
5
5
  runScript,
6
6
  startWorkflowExecution
7
- } from "./cli-1aqc46he.js";
7
+ } from "./cli-z46pnksz.js";
8
8
  import {
9
9
  getScript
10
- } from "./cli-4f6vw5vy.js";
10
+ } from "./cli-qwgtacd6.js";
11
11
  import {
12
12
  createTaskWithSiblingAwareness,
13
13
  scheduleContextKey
14
- } from "./cli-aqr96mny.js";
14
+ } from "./cli-y4ycrnjc.js";
15
15
  import {
16
16
  getDb,
17
17
  getDueScheduledTasks,
@@ -21,7 +21,7 @@ import {
21
21
  init_telemetry,
22
22
  telemetry,
23
23
  updateScheduledTask
24
- } from "./cli-4ke1amr9.js";
24
+ } from "./cli-ncfgsqbd.js";
25
25
  import {
26
26
  __commonJS,
27
27
  __require,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getDb,
3
3
  init_db
4
- } from "./cli-4ke1amr9.js";
4
+ } from "./cli-ncfgsqbd.js";
5
5
 
6
6
  // src/be/users.ts
7
7
  init_db();
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  createAdditiveBuffer,
3
3
  extractSlackMessageText
4
- } from "./cli-xqzvygxp.js";
4
+ } from "./cli-bgvskydy.js";
5
5
  import {
6
6
  getSlackApp,
7
7
  registerTreeMessage
8
- } from "./cli-f1f82qgv.js";
8
+ } from "./cli-trmapn9k.js";
9
9
  import {
10
10
  buildBufferFlushBlocks
11
11
  } from "./cli-6xd0bvf8.js";
12
12
  import {
13
13
  createTaskWithSiblingAwareness,
14
14
  slackContextKey
15
- } from "./cli-aqr96mny.js";
15
+ } from "./cli-y4ycrnjc.js";
16
16
  import {
17
17
  getLatestActiveTaskInThread,
18
18
  getLeadAgent,
@@ -20,7 +20,7 @@ import {
20
20
  init_db,
21
21
  init_registry,
22
22
  registerTemplate
23
- } from "./cli-4ke1amr9.js";
23
+ } from "./cli-ncfgsqbd.js";
24
24
 
25
25
  // src/slack/event-dedup.ts
26
26
  var DEFAULT_TTL_MS = 300000;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getScriptApiTypes,
3
3
  require_typescript
4
- } from "./cli-4f6vw5vy.js";
4
+ } from "./cli-qwgtacd6.js";
5
5
  import {
6
6
  deleteSwarmConfigByKey,
7
7
  getAgentById,
@@ -10,7 +10,7 @@ import {
10
10
  getSwarmConfigs,
11
11
  init_db,
12
12
  upsertSwarmConfig
13
- } from "./cli-4ke1amr9.js";
13
+ } from "./cli-ncfgsqbd.js";
14
14
  import {
15
15
  init_secret_scrubber,
16
16
  scrubSecrets
@@ -468,6 +468,8 @@ export interface SwarmSdk {
468
468
  slack_startThread(args: { channelId: string; message: string }): Promise<unknown>;
469
469
  slack_uploadFile(args: Record<string, unknown>): Promise<unknown>;
470
470
  slack_downloadFile(args: { url: string }): Promise<unknown>;
471
+ slack_delete(args: { channelId: string; messageTs: string }): Promise<unknown>;
472
+ slack_update(args: { channelId: string; messageTs: string; message: string }): Promise<unknown>;
471
473
 
472
474
  // --- write: messaging (internal) ---
473
475
  message_post(args: { channel?: string; content: string; to?: string }): Promise<unknown>;
@@ -18,7 +18,7 @@ import {
18
18
  withSpan,
19
19
  withSpanContext,
20
20
  writeSkillsToFilesystem
21
- } from "./cli-dza5039b.js";
21
+ } from "./cli-4xyj9jtq.js";
22
22
  import {
23
23
  authJsonToCredentialSelection,
24
24
  credentialsToAuthJson,
@@ -40,10 +40,10 @@ import {
40
40
  import {
41
41
  ensure,
42
42
  initialize
43
- } from "./cli-r3y5chyg.js";
43
+ } from "./cli-gtkqc144.js";
44
44
  import {
45
45
  validateJsonSchema
46
- } from "./cli-1aqc46he.js";
46
+ } from "./cli-z46pnksz.js";
47
47
  import {
48
48
  getApiKey
49
49
  } from "./cli-f14fvzag.js";
@@ -79,7 +79,7 @@ import {
79
79
  resolveTaskModelSelection,
80
80
  resolveTemplateAsync,
81
81
  telemetry
82
- } from "./cli-4ke1amr9.js";
82
+ } from "./cli-ncfgsqbd.js";
83
83
  import {
84
84
  init_credentials,
85
85
  resolveCredentialPools
@@ -1558,7 +1558,42 @@ async function listSwarmAutostashes(clonePath, role) {
1558
1558
  return [];
1559
1559
  }
1560
1560
  }
1561
- async function refreshExistingRepoForTask(repoConfig, role) {
1561
+ var CONTINUATION_TASK_TYPES = new Set([
1562
+ "resume",
1563
+ "follow-up",
1564
+ "reroute-decision",
1565
+ "agentmail-reply",
1566
+ "github-comment",
1567
+ "github-review",
1568
+ "gitlab-comment",
1569
+ "gitlab-ci"
1570
+ ]);
1571
+ var ACTIVE_PARENT_STATUSES = new Set(["pending", "in_progress", "offered", "paused"]);
1572
+ async function isFirstKickoffTask(task, fetchParentTaskStatus) {
1573
+ if (task?.taskType && CONTINUATION_TASK_TYPES.has(task.taskType))
1574
+ return false;
1575
+ if (task?.parentTaskId && fetchParentTaskStatus) {
1576
+ const parentStatus = await fetchParentTaskStatus(task.parentTaskId);
1577
+ if (parentStatus && ACTIVE_PARENT_STATUSES.has(parentStatus))
1578
+ return false;
1579
+ }
1580
+ return true;
1581
+ }
1582
+ async function fetchTaskStatus(apiUrl, apiKey, taskId) {
1583
+ const headers = {};
1584
+ if (apiKey)
1585
+ headers.Authorization = `Bearer ${apiKey}`;
1586
+ try {
1587
+ const response = await fetch(`${apiUrl}/api/tasks/${taskId}`, { headers });
1588
+ if (!response.ok)
1589
+ return null;
1590
+ const data = await response.json();
1591
+ return data.status ?? null;
1592
+ } catch {
1593
+ return null;
1594
+ }
1595
+ }
1596
+ async function refreshExistingRepoForTask(repoConfig, role, isFirstKickoff) {
1562
1597
  const { name, clonePath, defaultBranch } = repoConfig;
1563
1598
  const statusResult = await Bun.$`env -u GIT_DIR -u GIT_WORK_TREE -u GIT_INDEX_FILE -u GIT_PREFIX git -C ${clonePath} status --porcelain`.quiet();
1564
1599
  const statusOutput = statusResult.text().trim();
@@ -1575,13 +1610,24 @@ async function refreshExistingRepoForTask(repoConfig, role) {
1575
1610
  return `The repo "${name}" at ${clonePath} has uncommitted changes, but auto-stash failed: ${errorMsg}. A git pull was skipped to avoid losing work.`;
1576
1611
  }
1577
1612
  }
1613
+ const fetchSpec = `${defaultBranch}:refs/remotes/origin/${defaultBranch}`;
1614
+ const remoteRef = `refs/remotes/origin/${defaultBranch}`;
1578
1615
  try {
1579
- console.log(`[${role}] Refreshing ${name} from origin/${defaultBranch}...`);
1580
- const fetchSpec = `${defaultBranch}:refs/remotes/origin/${defaultBranch}`;
1581
- const remoteRef = `refs/remotes/origin/${defaultBranch}`;
1582
1616
  await Bun.$`env -u GIT_DIR -u GIT_WORK_TREE -u GIT_INDEX_FILE -u GIT_PREFIX git -C ${clonePath} fetch origin ${fetchSpec}`.quiet();
1583
- await Bun.$`env -u GIT_DIR -u GIT_WORK_TREE -u GIT_INDEX_FILE -u GIT_PREFIX git -C ${clonePath} merge --no-edit --no-stat ${remoteRef}`.quiet();
1584
- console.log(`[${role}] Refreshed ${name}`);
1617
+ if (isFirstKickoff) {
1618
+ console.log(`[${role}] First kickoff for ${name} — resetting to ${remoteRef}...`);
1619
+ try {
1620
+ await Bun.$`env -u GIT_DIR -u GIT_WORK_TREE -u GIT_INDEX_FILE -u GIT_PREFIX git -C ${clonePath} checkout ${defaultBranch}`.quiet();
1621
+ } catch {
1622
+ await Bun.$`env -u GIT_DIR -u GIT_WORK_TREE -u GIT_INDEX_FILE -u GIT_PREFIX git -C ${clonePath} checkout -B ${defaultBranch} ${remoteRef}`.quiet();
1623
+ }
1624
+ await Bun.$`env -u GIT_DIR -u GIT_WORK_TREE -u GIT_INDEX_FILE -u GIT_PREFIX git -C ${clonePath} reset --hard ${remoteRef}`.quiet();
1625
+ console.log(`[${role}] Reset ${name} to ${remoteRef}`);
1626
+ } else {
1627
+ console.log(`[${role}] Refreshing ${name} from ${remoteRef}...`);
1628
+ await Bun.$`env -u GIT_DIR -u GIT_WORK_TREE -u GIT_INDEX_FILE -u GIT_PREFIX git -C ${clonePath} merge --no-edit --no-stat ${remoteRef}`.quiet();
1629
+ console.log(`[${role}] Refreshed ${name}`);
1630
+ }
1585
1631
  return null;
1586
1632
  } catch (err) {
1587
1633
  const errorMsg = scrubSecrets(err.message);
@@ -1611,7 +1657,7 @@ async function installRepoHooksForTask(repoConfig, role) {
1611
1657
  console.warn(`[${role}] Could not install git hooks for ${repoConfig.name}: ${errorMsg}`);
1612
1658
  }
1613
1659
  }
1614
- async function ensureRepoForTask(repoConfig, role) {
1660
+ async function ensureRepoForTask(repoConfig, role, isFirstKickoff = false) {
1615
1661
  const { url, name, clonePath, defaultBranch } = repoConfig;
1616
1662
  try {
1617
1663
  const gitHeadExists = await Bun.file(`${clonePath}/.git/HEAD`).exists();
@@ -1632,7 +1678,7 @@ async function ensureRepoForTask(repoConfig, role) {
1632
1678
  console.log(`[${role}] Cloned ${name}`);
1633
1679
  } else {
1634
1680
  console.log(`[${role}] Repo ${name} already cloned at ${clonePath}`);
1635
- warning = await refreshExistingRepoForTask({ name, clonePath, defaultBranch }, role);
1681
+ warning = await refreshExistingRepoForTask({ name, clonePath, defaultBranch }, role, isFirstKickoff);
1636
1682
  }
1637
1683
  await installRepoHooksForTask(repoConfig, role);
1638
1684
  const claudeMd = await readClaudeMd(clonePath, role);
@@ -4510,7 +4556,7 @@ ${additionalSystemPrompt}` : basePrompt;
4510
4556
  clonePath: `/workspace/personal/repos/${task.vcsRepo.split("/").pop() || task.vcsRepo}`,
4511
4557
  defaultBranch: "main"
4512
4558
  };
4513
- const repoContext = await ensureRepoForTask(effectiveConfig, role);
4559
+ const repoContext = await ensureRepoForTask(effectiveConfig, role, false);
4514
4560
  if (repoContext?.clonePath) {
4515
4561
  resumeCwd = repoContext.clonePath;
4516
4562
  }
@@ -4740,7 +4786,8 @@ ${additionalSystemPrompt}` : basePrompt;
4740
4786
  clonePath: `/workspace/personal/repos/${taskVcsRepo.split("/").pop() || taskVcsRepo}`,
4741
4787
  defaultBranch: "main"
4742
4788
  };
4743
- const repoResult = await ensureRepoForTask(effectiveConfig, role);
4789
+ const isFirstKickoff = await isFirstKickoffTask(taskObj, (parentTaskId) => fetchTaskStatus(apiUrl, apiKey, parentTaskId));
4790
+ const repoResult = await ensureRepoForTask(effectiveConfig, role, isFirstKickoff);
4744
4791
  currentRepoContext = {
4745
4792
  ...repoResult,
4746
4793
  guidelines: repoConfig?.guidelines ?? null
@@ -25,7 +25,7 @@ import {
25
25
  import {
26
26
  init_package,
27
27
  package_default
28
- } from "./cli-kavm2cv5.js";
28
+ } from "./cli-c3frqf65.js";
29
29
  import {
30
30
  init_secret_scrubber,
31
31
  scrubSecrets
@@ -2504,13 +2504,9 @@ Use this to debug issues and propose improvements to your own infrastructure.
2504
2504
  category: "system"
2505
2505
  });
2506
2506
  registerTemplate({
2507
- eventType: "system.agent.context_mode",
2507
+ eventType: "system.agent.script_rubric",
2508
2508
  header: "",
2509
2509
  defaultBody: `
2510
- ### Context Window Management
2511
-
2512
- You have access to the \`context-mode\` MCP tools (\`batch_execute\`, \`execute\`, \`execute_file\`, \`search\`, \`fetch_and_index\`, \`index\`) which compress tool output to save context window space. For data-heavy operations (web fetches, large file reads, CLI output processing), prefer these over raw Bash/WebFetch to avoid flooding your context window with raw output.
2513
-
2514
2510
  ### Agent Scripts — for bulk, repetitive, or data-heavy work
2515
2511
 
2516
2512
  Use **scripts** (\`script-upsert\` + \`script-run\`) when a task involves repetitive SDK calls, large data processing, or deterministic multi-step pipelines. Scripts run out-of-process and return only their final result.
@@ -2519,19 +2515,48 @@ Use **scripts** (\`script-upsert\` + \`script-run\`) when a task involves repeti
2519
2515
 
2520
2516
  | Situation | Preferred approach |
2521
2517
  |---|---|
2522
- | 1–10 SDK calls, result fits in context | Direct tool call |
2518
+ | 1–10 SDK calls, result fits in context | Direct tool call. Do not script below the ~10-call threshold. |
2523
2519
  | 10+ items, bulk/fan-out SDK ops | **Script** (\`script-run\` with inline source or named) |
2524
2520
  | Heavy data (fetch + parse + transform) | **Script** or \`ctx_*\` (context-mode) |
2525
2521
  | Single expensive web fetch | \`ctx_fetch_and_index\` (context-mode) |
2526
2522
  | Multi-agent fan-out, parallel work, deterministic pipeline | **Workflow** |
2527
2523
  | One-off bash/TS with no reuse needed | \`code-mode run\` (Bash) |
2528
2524
 
2525
+ **Script persistence guardrail:** use a named script only when the logic will be invoked ≥2 times by you, another agent, or a workflow. For genuine one-offs, use inline \`script-run\` so the catalog does not accumulate scratch-* auto-saves.
2526
+
2527
+ **Worked example:** workflow triage that previously cost ~26 underlying calls can return one ~4.3k-token result in ~13s, a ~90-95% context reduction.
2528
+
2529
2529
  The 5 script tools (\`script-search\`, \`script-run\`, \`script-upsert\`, \`script-delete\`, \`script-query-types\`) are deferred tools. Call ToolSearch to load \`script-upsert\`, \`script-run\`, and \`script-query-types\` before using them.
2530
2530
 
2531
2531
  **Key gotchas:**
2532
2532
  - \`agentId\` IS propagated to scripts via the \`X-Agent-ID\` header.
2533
2533
  - \`taskId\` is NOT propagated to scripts — there is no ambient task context. Pass \`taskId\` explicitly via \`args\` if the script needs to call \`ctx.swarm.task_storeProgress\`.
2534
2534
  - Use \`script-query-types\` to inspect the live \`swarm-sdk.d.ts\` before authoring a complex script.
2535
+ - Typed API connections: a lead-registered \`script_connections\` entry exposes a typed \`ctx.api.<slug>.<method>(...)\` client in scripts.
2536
+ - \`ctx.api\` clients auto-inject the configured credential at egress, so scripts calling an allow-listed external API should prefer \`ctx.api\` over hand-written \`[REDACTED:<KEY>]\` Authorization headers.
2537
+ - Registration is lead-only; workers should document the connection spec and hand it to the lead to register.
2538
+ `,
2539
+ variables: [],
2540
+ category: "system"
2541
+ });
2542
+ registerTemplate({
2543
+ eventType: "system.agent.context_mode",
2544
+ header: "",
2545
+ defaultBody: `
2546
+ ### Context Window Management
2547
+
2548
+ You have access to the \`context-mode\` MCP tools (\`batch_execute\`, \`execute\`, \`execute_file\`, \`search\`, \`fetch_and_index\`, \`index\`) which compress tool output to save context window space. For data-heavy operations (web fetches, large file reads, CLI output processing), prefer these over raw Bash/WebFetch to avoid flooding your context window with raw output.
2549
+
2550
+ {{@template[system.agent.script_rubric]}}
2551
+
2552
+ ### Scheduling — Pick the Right targetType
2553
+
2554
+ When creating a schedule, match \`targetType\` to the work being fired:
2555
+ - Use \`targetType: "workflow"\` with \`workflowId\` when the schedule's only job is to start a workflow.
2556
+ - Use \`targetType: "script"\` with \`scriptName\` and optional \`scriptArgs\` when it only needs to run a catalog script.
2557
+ - Use \`targetType: "agent-task"\` only when a reasoning agent genuinely needs to be in the loop for judgment, open-ended work, or tool orchestration that is not already captured by a workflow or script.
2558
+
2559
+ Do not create an \`agent-task\` schedule whose \`taskTemplate\` just says to trigger a workflow or script. Workflow/script targets dispatch directly; agent-task fields such as \`targetAgentId\`, \`model\`, \`taskTemplate\`, \`priority\`, and \`tags\` do not drive those direct runs, and workflow cooldowns still gate workflow targets.
2535
2560
  `,
2536
2561
  variables: [],
2537
2562
  category: "system"
@@ -2779,6 +2804,8 @@ Honor this requester profile in tone, depth, and format where it doesn't conflic
2779
2804
  {{@template[system.agent.worker]}}
2780
2805
  {{@template[system.agent.filesystem]}}
2781
2806
  {{@template[system.agent.self_awareness]}}
2807
+ {{@template[system.agent.script_rubric]}}
2808
+ {{@template[system.agent.seed_scripts]}}
2782
2809
 
2783
2810
  {{@template[system.agent.system]}}
2784
2811
  {{@template[system.agent.share_urls]}}
@@ -6596,6 +6623,15 @@ function getScheduledTasks(filters, opts) {
6596
6623
  query += " AND scriptName = ?";
6597
6624
  params.push(filters.scriptName);
6598
6625
  }
6626
+ if (filters?.consecutiveErrorsMin !== undefined) {
6627
+ query += " AND consecutiveErrors >= ?";
6628
+ params.push(filters.consecutiveErrorsMin);
6629
+ }
6630
+ if (filters?.lastRunStatus === "failed") {
6631
+ query += " AND consecutiveErrors > 0";
6632
+ } else if (filters?.lastRunStatus === "succeeded") {
6633
+ query += " AND lastRunAt IS NOT NULL AND consecutiveErrors = 0";
6634
+ }
6599
6635
  if (filters?.hideCompleted !== false) {
6600
6636
  query += " AND NOT (scheduleType = 'one_time' AND enabled = 0)";
6601
6637
  }
@@ -7257,6 +7293,26 @@ function listWorkflows(filters, opts) {
7257
7293
  query += " AND enabled = ?";
7258
7294
  params.push(filters.enabled ? 1 : 0);
7259
7295
  }
7296
+ if (filters?.lastRunStatus !== undefined) {
7297
+ query += " AND (SELECT status FROM workflow_runs WHERE workflowId = workflows.id ORDER BY startedAt DESC LIMIT 1) = ?";
7298
+ params.push(filters.lastRunStatus);
7299
+ }
7300
+ if (filters?.consecutiveErrorsMin !== undefined) {
7301
+ query += ` AND (
7302
+ SELECT COUNT(*)
7303
+ FROM workflow_runs wr
7304
+ WHERE wr.workflowId = workflows.id
7305
+ AND wr.status = 'failed'
7306
+ AND NOT EXISTS (
7307
+ SELECT 1
7308
+ FROM workflow_runs newer_non_failed
7309
+ WHERE newer_non_failed.workflowId = wr.workflowId
7310
+ AND newer_non_failed.status != 'failed'
7311
+ AND newer_non_failed.startedAt > wr.startedAt
7312
+ )
7313
+ ) >= ?`;
7314
+ params.push(filters.consecutiveErrorsMin);
7315
+ }
7260
7316
  query += " ORDER BY lastUpdatedAt DESC";
7261
7317
  const rows = getDb().prepare(query).all(...params);
7262
7318
  return opts?.slim ? rows.map(rowToWorkflowSummary) : rows.map(rowToWorkflow);
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  recordUnmappedIdentity
3
- } from "./cli-2b0ew5v8.js";
3
+ } from "./cli-c9mtm09b.js";
4
4
  import {
5
5
  findOrCreateUserByEmail,
6
6
  findUserByExternalId,
7
7
  linkIdentity
8
- } from "./cli-0d404x64.js";
8
+ } from "./cli-h3k622d0.js";
9
9
  import {
10
10
  getKv,
11
11
  init_db,
12
12
  upsertKv
13
- } from "./cli-4ke1amr9.js";
13
+ } from "./cli-ncfgsqbd.js";
14
14
 
15
15
  // src/slack/enrich.ts
16
16
  init_db();
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  embedScript
3
- } from "./cli-h3vhr1gj.js";
3
+ } from "./cli-30bbaveh.js";
4
4
  import {
5
5
  computeContentHash,
6
6
  decryptSecret,
@@ -10,7 +10,7 @@ import {
10
10
  getSwarmConfigs,
11
11
  init_crypto,
12
12
  init_db
13
- } from "./cli-4ke1amr9.js";
13
+ } from "./cli-ncfgsqbd.js";
14
14
  import {
15
15
  init_zod
16
16
  } from "./cli-q21d49ac.js";
@@ -17,7 +17,7 @@ import {
17
17
  init_templates1 as init_templates,
18
18
  normalizeDateRequired,
19
19
  resolveTemplate
20
- } from "./cli-4ke1amr9.js";
20
+ } from "./cli-ncfgsqbd.js";
21
21
 
22
22
  // src/be/db-queries/tracker.ts
23
23
  init_date_utils();
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getDb,
3
3
  init_db
4
- } from "./cli-4ke1amr9.js";
4
+ } from "./cli-ncfgsqbd.js";
5
5
 
6
6
  // src/be/seed-pricing.ts
7
7
  init_db();
@@ -25,7 +25,7 @@ import {
25
25
  getTaskById,
26
26
  init_db,
27
27
  setSlackMessageTracking
28
- } from "./cli-4ke1amr9.js";
28
+ } from "./cli-ncfgsqbd.js";
29
29
  import {
30
30
  require_receiver,
31
31
  require_sender,
@@ -54988,13 +54988,13 @@ async function initSlackApp() {
54988
54988
  socketMode: true,
54989
54989
  logLevel: import_bolt.LogLevel.DEBUG
54990
54990
  });
54991
- const { registerMessageHandler } = await import("./handlers-mcmg5qgc.js");
54992
- const { registerCommandHandler } = await import("./commands-t3rdvb55.js");
54993
- const { registerActionHandlers } = await import("./actions-a4crgvtd.js");
54991
+ const { registerMessageHandler } = await import("./handlers-6b44317z.js");
54992
+ const { registerCommandHandler } = await import("./commands-z5dbwta3.js");
54993
+ const { registerActionHandlers } = await import("./actions-q4n7cz6e.js");
54994
54994
  registerMessageHandler(app);
54995
54995
  registerCommandHandler(app);
54996
54996
  registerActionHandlers(app);
54997
- const { createAssistant } = await import("./assistant-0jm4vy8r.js");
54997
+ const { createAssistant } = await import("./assistant-0x8ey0vs.js");
54998
54998
  app.assistant(createAssistant());
54999
54999
  return app;
55000
55000
  }
@@ -3,7 +3,7 @@ import {
3
3
  getAgentById,
4
4
  getInProgressTasksByContextKey,
5
5
  init_db
6
- } from "./cli-4ke1amr9.js";
6
+ } from "./cli-ncfgsqbd.js";
7
7
 
8
8
  // src/tasks/context-key.ts
9
9
  var SEPARATOR = ":";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  init_package,
3
3
  package_default
4
- } from "./cli-kavm2cv5.js";
4
+ } from "./cli-c3frqf65.js";
5
5
 
6
6
  // src/commands/shared/client-config.ts
7
7
  init_package();
@@ -9,11 +9,11 @@ import {
9
9
  getScriptVersion,
10
10
  listRelationalCredentialBindings,
11
11
  validateScriptImports
12
- } from "./cli-4f6vw5vy.js";
12
+ } from "./cli-qwgtacd6.js";
13
13
  import {
14
14
  withSiblingAwareness,
15
15
  workflowContextKey
16
- } from "./cli-aqr96mny.js";
16
+ } from "./cli-y4ycrnjc.js";
17
17
  import {
18
18
  getAppUrl
19
19
  } from "./cli-dh55d5fg.js";
@@ -62,7 +62,7 @@ import {
62
62
  telemetry,
63
63
  updateWorkflowRun,
64
64
  updateWorkflowRunStep
65
- } from "./cli-4ke1amr9.js";
65
+ } from "./cli-ncfgsqbd.js";
66
66
  import {
67
67
  init_zod
68
68
  } from "./cli-q21d49ac.js";
@@ -2515,7 +2515,7 @@ class HumanInTheLoopExecutor extends BaseExecutor {
2515
2515
  }
2516
2516
  if (notification.channel === "slack") {
2517
2517
  try {
2518
- const { getSlackApp } = await import("./app-va5mr9yw.js");
2518
+ const { getSlackApp } = await import("./app-es4nzc71.js");
2519
2519
  const slackApp = getSlackApp();
2520
2520
  if (!slackApp) {
2521
2521
  console.warn("[HITL] Slack not initialized — cannot send notification");
@@ -2629,7 +2629,7 @@ class NotifyExecutor extends BaseExecutor {
2629
2629
  }
2630
2630
  }
2631
2631
  case "slack": {
2632
- const { getSlackApp } = await import("./app-va5mr9yw.js");
2632
+ const { getSlackApp } = await import("./app-es4nzc71.js");
2633
2633
  const app = getSlackApp();
2634
2634
  if (!app) {
2635
2635
  return {