@desplega.ai/agent-swarm 2.5.1 → 2.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{acp-adapter-7g6bpwbk.js → acp-adapter-csh0zz3b.js} +1 -1
- package/dist/{actions-w8xd014k.js → actions-6xx079d1.js} +17 -17
- package/dist/{amp-adapter-z4qvhacj.js → amp-adapter-8n6f0hz8.js} +2 -2
- package/dist/{app-nndcvftq.js → app-ft6r6v23.js} +3 -3
- package/dist/{assistant-hjmqyscx.js → assistant-vt2cyfzd.js} +18 -18
- package/dist/{boot-reembed-r8rhf9h8.js → boot-reembed-r3e808ky.js} +1 -1
- package/dist/{boot-reembed-vwcj2y5d.js → boot-reembed-tgrfy27t.js} +1 -1
- package/dist/{boot-scrub-sweep-fr9q36ne.js → boot-scrub-sweep-masdwxkm.js} +2 -2
- package/dist/{boot-seeds-9jqwnegq.js → boot-seeds-0n82qc7q.js} +4 -4
- package/dist/{claude-adapter-2f8b85df.js → claude-adapter-s7j47k06.js} +2 -2
- package/dist/{claude-managed-setup-c3hp36ph.js → claude-managed-setup-3hzrgrnk.js} +1 -1
- package/dist/{claude-sdk-session-05kat8rv.js → claude-sdk-session-0zrdzyx2.js} +6905 -6855
- package/dist/{cli-mz2ygeyq.js → cli-0vgy5wfw.js} +2 -2
- package/dist/{cli-eym3jg7w.js → cli-14v1sxxy.js} +6 -6
- package/dist/{cli-e9btqw4y.js → cli-15xd0j7w.js} +18 -13
- package/dist/{cli-v2g93k4v.js → cli-3e9vs93g.js} +4 -4
- package/dist/{cli-1dp1zj04.js → cli-4qkg9968.js} +3 -3
- package/dist/{cli-ba8ne1es.js → cli-4rvr7zfx.js} +10 -0
- package/dist/{cli-rngde2jv.js → cli-6y43v79h.js} +1 -1
- package/dist/{cli-z63a269p.js → cli-7ccf7akh.js} +1 -1
- package/dist/{cli-z2dv25mf.js → cli-86zpfje5.js} +116 -5
- package/dist/{cli-fes51ya2.js → cli-aaqnqpyw.js} +2 -2
- package/dist/{cli-qfm6my86.js → cli-b1tv22wr.js} +1 -1
- package/dist/{cli-xc65x52q.js → cli-b63d08rs.js} +1 -1
- package/dist/{cli-gwcf52gz.js → cli-b6tnjdvx.js} +11 -7
- package/dist/{cli-9mm5ade4.js → cli-bpbcpd8b.js} +1 -1
- package/dist/{cli-qfjm4gvt.js → cli-cf63dnxj.js} +2 -2
- package/dist/{cli-q9pzwxvk.js → cli-csh8fnbg.js} +82 -16
- package/dist/{cli-0jy85zz4.js → cli-cyfgxnvb.js} +7 -7
- package/dist/{cli-y3zyaee5.js → cli-d172svcw.js} +5 -5
- package/dist/{cli-mq7kg1b1.js → cli-e91vshb1.js} +41 -6
- package/dist/{cli-cah5detr.js → cli-edtm741g.js} +5 -5
- package/dist/{cli-ajqhxtnz.js → cli-f3pfn4x3.js} +1 -1
- package/dist/{cli-hadv0725.js → cli-f55b6ky0.js} +1 -1
- package/dist/{cli-r9fy0ddc.js → cli-fgn7yg5r.js} +1 -1
- package/dist/{cli-kcsd1ez8.js → cli-h5d22pfs.js} +249 -68
- package/dist/{cli-2wba1ac9.js → cli-ha22h0eg.js} +20 -20
- package/dist/{cli-pyy4c9ch.js → cli-j3dwd4kz.js} +173 -134
- package/dist/{cli-j1eghqfm.js → cli-jmcjbjkt.js} +1 -1
- package/dist/{cli-22rmcjkg.js → cli-kcnwn85g.js} +4 -3
- package/dist/{cli-rh5smt8t.js → cli-mntxtkhn.js} +12 -2
- package/dist/{cli-2jg61wab.js → cli-n2918sed.js} +9 -9
- package/dist/{cli-3ee5z0q0.js → cli-qrjv7t18.js} +1 -1
- package/dist/{cli-sn1vbtg2.js → cli-vaxw3bg0.js} +3 -3
- package/dist/{cli-cwyafhw1.js → cli-wadzapwb.js} +1 -1
- package/dist/{cli-jpxsrxcb.js → cli-xw9q173h.js} +1 -1
- package/dist/{cli-znvq0k3t.js → cli-xzge46sj.js} +2 -2
- package/dist/{cli-nj12tn2c.js → cli-y3dzwyy3.js} +3 -3
- package/dist/{cli-xd4eqtr2.js → cli-ydg6ep51.js} +1 -1
- package/dist/cli.js +16 -15
- package/dist/{codex-adapter-p4ptwar5.js → codex-adapter-brh2tcxr.js} +1 -1
- package/dist/{codex-session-runner-964c7dnk.js → codex-session-runner-0dnj21qs.js} +1 -1
- package/dist/{commands-mbvhbrcy.js → commands-1cnvseqx.js} +2 -2
- package/dist/{controller-gnq1k1mf.js → controller-kc7s9xhn.js} +2 -2
- package/dist/{controllers-connect-6dkm71tg.js → controllers-connect-jzx7t4bn.js} +18 -18
- package/dist/{cursor-adapter-yq5xgfcg.js → cursor-adapter-qpwp5sfg.js} +1 -1
- package/dist/{db-af9y8nkf.js → db-4vq88jkc.js} +3 -3
- package/dist/{db-88wcymxt.js → db-v5ytg5pw.js} +1 -1
- package/dist/{dispatcher-606ydx5v.js → dispatcher-trtcrqae.js} +16 -16
- package/dist/{dsh-adapter-tvhc4k2d.js → dsh-adapter-f20xwn1z.js} +1 -1
- package/dist/{external-channel-y8q5z8z2.js → external-channel-n9bymc2n.js} +2 -2
- package/dist/{grok-adapter-39aha52t.js → grok-adapter-4kpmmnr6.js} +2 -2
- package/dist/{handlers-rk9dqech.js → handlers-ptsraqa8.js} +19 -19
- package/dist/{heartbeat-jfe9zfjr.js → heartbeat-60qtxtjf.js} +19 -19
- package/dist/{hook-ffevzed1.js → hook-ngtvh729.js} +1 -1
- package/dist/{hook-b1mez1m8.js → hook-rbktcstg.js} +1 -1
- package/dist/{http-d5b44f1r.js → http-z8xy72gp.js} +334 -86
- package/dist/{index-nq8hhv28.js → index-06qkmcx6.js} +10 -9
- package/dist/{index-d2qeem97.js → index-1cscynkb.js} +16 -16
- package/dist/{index-5en23s5z.js → index-a9nsavhx.js} +1 -1
- package/dist/{index-4q3vj1yr.js → index-r70q0xjx.js} +16 -16
- package/dist/{index-mj46rk9k.js → index-s193j5fh.js} +19 -19
- package/dist/{keepalive-wsby1btq.js → keepalive-a9srcphj.js} +3 -3
- package/dist/{lead-paa141j6.js → lead-3devneqy.js} +26 -26
- package/dist/{maintenance-vnshcyv9.js → maintenance-0er16h2y.js} +1 -1
- package/dist/{oauth-refresh-sweep-d6sqn5np.js → oauth-refresh-sweep-b65jcyw2.js} +2 -2
- package/dist/{onboard-nr4xhpzy.js → onboard-wqywz5py.js} +2 -2
- package/dist/{otel-impl-ytn9wyv9.js → otel-impl-vk32s884.js} +1 -1
- package/dist/{pricing-refresh-pva04zee.js → pricing-refresh-t27anv4z.js} +3 -3
- package/dist/rbac-roles-452665y0.js +26 -0
- package/dist/{rbac-roles-7rc1q3g4.js → rbac-roles-bmcgsxjn.js} +12 -2
- package/dist/{render-v2-pyfsg9zk.js → render-v2-0ttsk2j4.js} +3 -3
- package/dist/{resume-phj8xhqr.js → resume-a26kvr41.js} +5 -5
- package/dist/{session-access-jzx2z9h5.js → session-access-dgh9nkwk.js} +4 -4
- package/dist/{setup-rfg0f0sg.js → setup-9vc9qahm.js} +1 -1
- package/dist/{work-objects-44z2yjg8.js → work-objects-vn8nkxwn.js} +19 -19
- package/dist/{worker-zsfqzxhm.js → worker-1x1h8vnm.js} +26 -26
- package/openapi.json +463 -3
- package/package.json +4 -3
- package/src/be/db/session-tree.ts +89 -2
- package/src/be/db/session-visibility.ts +31 -0
- package/src/be/db/tasks/read.ts +18 -5
- package/src/be/db.ts +2 -0
- package/src/be/migrations/233_script_run_session_tokens.sql +8 -0
- package/src/be/migrations/235_chat_relay_defer.sql +86 -0
- package/src/be/migrations/237_session_inbox_cleanup.sql +75 -0
- package/src/be/rbac-roles.ts +138 -0
- package/src/be/scripts/run-credential.ts +64 -0
- package/src/be/scripts/run-saved.ts +3 -2
- package/src/be/users.ts +28 -4
- package/src/http/all-routes.ts +1 -0
- package/src/http/approval-requests.ts +46 -6
- package/src/http/index.ts +2 -0
- package/src/http/schedules.ts +26 -0
- package/src/http/scripts.ts +2 -2
- package/src/http/sessions.ts +93 -2
- package/src/http/user-roles.ts +173 -0
- package/src/http/users.ts +9 -0
- package/src/http/x.ts +2 -2
- package/src/integrations/chat-sdk/commands.ts +14 -1
- package/src/integrations/chat-sdk/inbound.ts +40 -5
- package/src/integrations/chat-sdk/outbound.ts +35 -10
- package/src/integrations/chat-sdk/reactions.ts +107 -0
- package/src/integrations/chat-sdk/relay.ts +75 -7
- package/src/integrations/chat-sdk/thread-buffer.ts +2 -0
- package/src/integrations/reaction-events.ts +20 -0
- package/src/providers/amp-adapter.ts +1 -1
- package/src/rbac/legacy-policy.ts +3 -0
- package/src/rbac/permissions.ts +8 -0
- package/src/scheduler/schedule-task.ts +44 -3
- package/src/scheduler/scheduler.ts +4 -4
- package/src/scripts-runtime/loader.ts +8 -1
- package/src/slack/ack.ts +2 -1
- package/src/slack/reaction-shortcode.ts +4 -7
- package/src/tasks/worker-follow-up.ts +30 -0
- package/src/tests/approval-requests-notifications.test.ts +189 -0
- package/src/tests/chat-sdk-commands.test.ts +12 -0
- package/src/tests/chat-sdk-inbound.test.ts +163 -9
- package/src/tests/chat-sdk-outbound-files.test.ts +9 -2
- package/src/tests/chat-sdk-relay.test.ts +361 -10
- package/src/tests/chat-sdk-tools.test.ts +104 -0
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/http-users.test.ts +38 -0
- package/src/tests/migration-237-session-inbox-cleanup.test.ts +136 -0
- package/src/tests/rbac-engine.test.ts +2 -0
- package/src/tests/rbac-roles.test.ts +10 -0
- package/src/tests/schedule-http-triage-tools.test.ts +44 -0
- package/src/tests/script-api-credential.test.ts +173 -0
- package/src/tests/script-connections.test.ts +4 -0
- package/src/tests/script-run-config-scope.test.ts +120 -0
- package/src/tests/script-run-token.test.ts +75 -0
- package/src/tests/scripts-http.test.ts +19 -0
- package/src/tests/sessions-tree.test.ts +242 -0
- package/src/tests/user-roles-http.test.ts +204 -0
- package/src/tests/workflow-hitl-dynamic-questions.test.ts +1 -1
- package/src/tools/chat-reply.ts +2 -0
- package/src/tools/schedules/patch-schedule.ts +18 -0
- package/src/tools/schedules/update-schedule.ts +18 -0
- package/src/types.ts +16 -0
- package/src/workflows/approval-notifications.ts +214 -0
- package/src/workflows/executors/human-in-the-loop.ts +11 -172
- package/src/workflows/executors/swarm-script.ts +2 -2
- package/templates/schedules/weekly-harness-upgrade-check/content.md +1 -1
- package/templates/skills/code-quality/content.md +1 -1
- package/dist/rbac-roles-ff1ffmec.js +0 -12
|
@@ -301,7 +301,7 @@ import {
|
|
|
301
301
|
hasCapability,
|
|
302
302
|
getEnabledCapabilities,
|
|
303
303
|
createServer
|
|
304
|
-
} from "./cli-
|
|
304
|
+
} from "./cli-h5d22pfs.js";
|
|
305
305
|
import {
|
|
306
306
|
chatThreadOfContextKey,
|
|
307
307
|
agentContextKey,
|
|
@@ -424,6 +424,7 @@ import {
|
|
|
424
424
|
init_session_moves,
|
|
425
425
|
getSessionReadState,
|
|
426
426
|
getSessionTree,
|
|
427
|
+
triageSessionList,
|
|
427
428
|
init_session_tree,
|
|
428
429
|
setHumanFreeQueueListener,
|
|
429
430
|
drainHumanFreeReclassifyQueue,
|
|
@@ -750,31 +751,39 @@ import {
|
|
|
750
751
|
countScriptRunJournalSteps2,
|
|
751
752
|
countScriptRunJournalAgentTaskSteps2,
|
|
752
753
|
init_db3
|
|
753
|
-
} from "./cli-
|
|
754
|
+
} from "./cli-csh8fnbg.js";
|
|
754
755
|
import {
|
|
756
|
+
PRIMARY_ROLE_NAMES2,
|
|
755
757
|
getUserGrant2,
|
|
758
|
+
listUserRoles2,
|
|
759
|
+
listRbacRoles2,
|
|
760
|
+
InvalidRoleSetError2,
|
|
761
|
+
LastAdminError2,
|
|
762
|
+
assertNotLastAdmin2,
|
|
763
|
+
setUserRoles2,
|
|
756
764
|
init_rbac_roles
|
|
757
|
-
} from "./cli-
|
|
758
|
-
import"./cli-
|
|
765
|
+
} from "./cli-86zpfje5.js";
|
|
766
|
+
import"./cli-3e9vs93g.js";
|
|
759
767
|
import {
|
|
760
768
|
normalizeModelKey
|
|
761
|
-
} from "./cli-
|
|
769
|
+
} from "./cli-bpbcpd8b.js";
|
|
762
770
|
import {
|
|
763
771
|
upsertModelCatalogOverlay,
|
|
764
772
|
deleteModelCatalogOverlay,
|
|
765
773
|
loadModelsCatalog,
|
|
766
774
|
requestModelCatalogRefresh2
|
|
767
|
-
} from "./cli-
|
|
775
|
+
} from "./cli-0vgy5wfw.js";
|
|
768
776
|
import {
|
|
769
777
|
AMP_ESTIMATE_MODELS,
|
|
770
778
|
ampBillsCacheWrites,
|
|
771
779
|
resolveAmpModel
|
|
772
|
-
} from "./cli-
|
|
780
|
+
} from "./cli-xw9q173h.js";
|
|
773
781
|
import {
|
|
774
782
|
automationIntegrationFixUrl,
|
|
775
783
|
preflightAutomation,
|
|
776
784
|
getAutomationSetupStates,
|
|
777
785
|
listEnabledAutomationPreflightInputs,
|
|
786
|
+
dispatchApprovalNotifications,
|
|
778
787
|
createApprovalFollowUpTask,
|
|
779
788
|
validateJsonSchema,
|
|
780
789
|
workflowSaveWarnings,
|
|
@@ -783,7 +792,7 @@ import {
|
|
|
783
792
|
generateEdges,
|
|
784
793
|
definitionNodeIds,
|
|
785
794
|
validateDefinition
|
|
786
|
-
} from "./cli-
|
|
795
|
+
} from "./cli-j3dwd4kz.js";
|
|
787
796
|
import {
|
|
788
797
|
require_dist2,
|
|
789
798
|
isInvalidClientError,
|
|
@@ -847,7 +856,7 @@ import {
|
|
|
847
856
|
MAX_SCRIPT_WALL_CLOCK_MS,
|
|
848
857
|
require_typescript2,
|
|
849
858
|
checkImportAllowlist,
|
|
850
|
-
|
|
859
|
+
runScriptWithRunCredential,
|
|
851
860
|
extractScriptSignature,
|
|
852
861
|
extractArgsJsonSchema,
|
|
853
862
|
checkQuickJSCompat,
|
|
@@ -863,14 +872,14 @@ import {
|
|
|
863
872
|
typecheckWithAmbient,
|
|
864
873
|
typecheckScript,
|
|
865
874
|
parseSkillContent
|
|
866
|
-
} from "./cli-
|
|
875
|
+
} from "./cli-e91vshb1.js";
|
|
867
876
|
import {
|
|
868
877
|
buildAuthorizationUrl,
|
|
869
878
|
exchangeAuthorizationCode,
|
|
870
879
|
oauthAppRowToProviderConfig,
|
|
871
880
|
forceRefreshAuthorizationOrThrow,
|
|
872
881
|
forceRefreshTokenOrThrow
|
|
873
|
-
} from "./cli-
|
|
882
|
+
} from "./cli-6y43v79h.js";
|
|
874
883
|
import {
|
|
875
884
|
signalProcessGroup,
|
|
876
885
|
detachedProcessGroup,
|
|
@@ -898,8 +907,8 @@ import {
|
|
|
898
907
|
getSlackApp2,
|
|
899
908
|
startSlackApp2,
|
|
900
909
|
stopSlackApp2
|
|
901
|
-
} from "./cli-
|
|
902
|
-
import"./cli-
|
|
910
|
+
} from "./cli-15xd0j7w.js";
|
|
911
|
+
import"./cli-b63d08rs.js";
|
|
903
912
|
import"./cli-qqzmjxkf.js";
|
|
904
913
|
import {
|
|
905
914
|
_fetchHolder,
|
|
@@ -919,7 +928,7 @@ import {
|
|
|
919
928
|
import {
|
|
920
929
|
retryFailedRun2,
|
|
921
930
|
cancelWorkflowRun2
|
|
922
|
-
} from "./cli-
|
|
931
|
+
} from "./cli-y3dzwyy3.js";
|
|
923
932
|
import {
|
|
924
933
|
duplicateGuardedQueryKey,
|
|
925
934
|
warnIfCorsAllowsAnyOrigin,
|
|
@@ -964,7 +973,7 @@ import {
|
|
|
964
973
|
bodyListTask,
|
|
965
974
|
describeRequestRoute,
|
|
966
975
|
route
|
|
967
|
-
} from "./cli-
|
|
976
|
+
} from "./cli-d172svcw.js";
|
|
968
977
|
import {
|
|
969
978
|
isMultiRuntimeEnabled
|
|
970
979
|
} from "./cli-e8xyjvfc.js";
|
|
@@ -995,7 +1004,7 @@ import {
|
|
|
995
1004
|
resolvePoolDelivery2,
|
|
996
1005
|
createPoolAgent2,
|
|
997
1006
|
init_db
|
|
998
|
-
} from "./cli-
|
|
1007
|
+
} from "./cli-4qkg9968.js";
|
|
999
1008
|
import {
|
|
1000
1009
|
RATING_MODEL_MAX_LENGTH,
|
|
1001
1010
|
REFERENCES_SOURCE_MAX_LENGTH,
|
|
@@ -1011,8 +1020,8 @@ import {
|
|
|
1011
1020
|
checkHeartbeatChecklist2,
|
|
1012
1021
|
runHeartbeatSweep2,
|
|
1013
1022
|
stopHeartbeat2
|
|
1014
|
-
} from "./cli-
|
|
1015
|
-
import"./cli-
|
|
1023
|
+
} from "./cli-n2918sed.js";
|
|
1024
|
+
import"./cli-ydg6ep51.js";
|
|
1016
1025
|
import {
|
|
1017
1026
|
import_websocket,
|
|
1018
1027
|
import_websocket_server
|
|
@@ -1021,7 +1030,7 @@ import {
|
|
|
1021
1030
|
runtimeSupervisorStatus,
|
|
1022
1031
|
startRuntimeSupervisor,
|
|
1023
1032
|
stopRuntimeSupervisor
|
|
1024
|
-
} from "./cli-
|
|
1033
|
+
} from "./cli-cyfgxnvb.js";
|
|
1025
1034
|
import"./cli-ns59dc6r.js";
|
|
1026
1035
|
import {
|
|
1027
1036
|
ACP_TARGET_IDS
|
|
@@ -1041,11 +1050,11 @@ import {
|
|
|
1041
1050
|
memoryRelevance,
|
|
1042
1051
|
isUnknownModelError,
|
|
1043
1052
|
writeSkillsToFilesystem
|
|
1044
|
-
} from "./cli-
|
|
1053
|
+
} from "./cli-wadzapwb.js";
|
|
1045
1054
|
import {
|
|
1046
1055
|
inviteEmailToSharedOrg,
|
|
1047
1056
|
ensureAgentFsCredentialsForAgent
|
|
1048
|
-
} from "./cli-
|
|
1057
|
+
} from "./cli-fgn7yg5r.js";
|
|
1049
1058
|
import {
|
|
1050
1059
|
Anthropic
|
|
1051
1060
|
} from "./cli-3qv8naq8.js";
|
|
@@ -1084,7 +1093,7 @@ import {
|
|
|
1084
1093
|
revokeAgentTokens,
|
|
1085
1094
|
fingerprintApiKey,
|
|
1086
1095
|
init_users
|
|
1087
|
-
} from "./cli-
|
|
1096
|
+
} from "./cli-b6tnjdvx.js";
|
|
1088
1097
|
import"./cli-v41kn3cd.js";
|
|
1089
1098
|
import"./cli-wgtk7xxr.js";
|
|
1090
1099
|
import"./cli-1f0gp9vz.js";
|
|
@@ -1099,7 +1108,7 @@ import {
|
|
|
1099
1108
|
clearAuditSink,
|
|
1100
1109
|
can,
|
|
1101
1110
|
init_rbac
|
|
1102
|
-
} from "./cli-
|
|
1111
|
+
} from "./cli-4rvr7zfx.js";
|
|
1103
1112
|
import {
|
|
1104
1113
|
ASSET_KEY_MAX_LENGTH,
|
|
1105
1114
|
normalizeAssetKey,
|
|
@@ -1136,6 +1145,8 @@ import {
|
|
|
1136
1145
|
AgentTaskSchema,
|
|
1137
1146
|
TaskAttachmentSchema,
|
|
1138
1147
|
UserSchema,
|
|
1148
|
+
RbacRoleSchema,
|
|
1149
|
+
UserRbacRolesSchema,
|
|
1139
1150
|
UserCommsPrefsSchema,
|
|
1140
1151
|
InboxItemTypeSchema,
|
|
1141
1152
|
InboxItemStatusSchema,
|
|
@@ -1246,7 +1257,7 @@ import {
|
|
|
1246
1257
|
KvKeySchema,
|
|
1247
1258
|
KvEntrySchema,
|
|
1248
1259
|
init_types
|
|
1249
|
-
} from "./cli-
|
|
1260
|
+
} from "./cli-mntxtkhn.js";
|
|
1250
1261
|
import {
|
|
1251
1262
|
IDENTITY_FIELD_BUDGETS,
|
|
1252
1263
|
IdentityFieldBudgetError,
|
|
@@ -1319,7 +1330,7 @@ import {
|
|
|
1319
1330
|
import {
|
|
1320
1331
|
init_package,
|
|
1321
1332
|
package_default
|
|
1322
|
-
} from "./cli-
|
|
1333
|
+
} from "./cli-kcnwn85g.js";
|
|
1323
1334
|
import {
|
|
1324
1335
|
realtimeBus,
|
|
1325
1336
|
init_bus
|
|
@@ -5989,6 +6000,7 @@ init_db3();
|
|
|
5989
6000
|
init_users();
|
|
5990
6001
|
init_rbac();
|
|
5991
6002
|
init_request_auth_context();
|
|
6003
|
+
init_secret_scrubber();
|
|
5992
6004
|
init_event_bus();
|
|
5993
6005
|
var QuestionSchema = object2({
|
|
5994
6006
|
id: string2(),
|
|
@@ -6154,14 +6166,15 @@ var createRoute = route({
|
|
|
6154
6166
|
notifications: array2(object2({
|
|
6155
6167
|
channel: _enum2(["slack", "email"]),
|
|
6156
6168
|
target: string2()
|
|
6157
|
-
})).optional()
|
|
6169
|
+
})).optional().describe("Where to announce the request. A Slack target (channel or user ID) gets a card with the title, the questions and a link to the dashboard page that answers it. Slack targets need a lead agent caller (403 otherwise). Email is not supported yet and is skipped.")
|
|
6158
6170
|
}),
|
|
6159
6171
|
responses: {
|
|
6160
6172
|
201: {
|
|
6161
6173
|
description: "Approval request created",
|
|
6162
6174
|
schema: object2({ approvalRequest: ApprovalRequestSchema })
|
|
6163
6175
|
},
|
|
6164
|
-
400: { description: "Validation error" }
|
|
6176
|
+
400: { description: "Validation error" },
|
|
6177
|
+
403: { description: "Slack notifications require a lead agent" }
|
|
6165
6178
|
},
|
|
6166
6179
|
auth: { apiKey: true }
|
|
6167
6180
|
});
|
|
@@ -6375,7 +6388,7 @@ async function handleApprovalRequests(req, res, pathSegments, queryParams) {
|
|
|
6375
6388
|
const parsed = await cancelRoute.parse(req, res, pathSegments, queryParams);
|
|
6376
6389
|
if (!parsed)
|
|
6377
6390
|
return true;
|
|
6378
|
-
const { principal, resolvedBy } = await
|
|
6391
|
+
const { principal, resolvedBy } = await approvalCallerPrincipal(req);
|
|
6379
6392
|
const result = await cancelApprovalRequest({
|
|
6380
6393
|
id: parsed.params.id,
|
|
6381
6394
|
reason: parsed.body.reason,
|
|
@@ -6411,6 +6424,14 @@ async function handleApprovalRequests(req, res, pathSegments, queryParams) {
|
|
|
6411
6424
|
const parsed = await createRoute.parse(req, res, pathSegments, queryParams);
|
|
6412
6425
|
if (!parsed)
|
|
6413
6426
|
return true;
|
|
6427
|
+
if (parsed.body.notifications?.some((notification) => notification.channel === "slack")) {
|
|
6428
|
+
const { principal } = await approvalCallerPrincipal(req);
|
|
6429
|
+
const decision = can({ principal, verb: "integration.slack.post", source: "http" });
|
|
6430
|
+
if (!decision.allow) {
|
|
6431
|
+
jsonError(res, SLACK_NOTIFICATION_REFUSED, 403);
|
|
6432
|
+
return true;
|
|
6433
|
+
}
|
|
6434
|
+
}
|
|
6414
6435
|
const id = crypto.randomUUID();
|
|
6415
6436
|
const auth = getRequestAuth(req);
|
|
6416
6437
|
const rawCallerAgentId = req.headers["x-agent-id"];
|
|
@@ -6428,6 +6449,18 @@ async function handleApprovalRequests(req, res, pathSegments, queryParams) {
|
|
|
6428
6449
|
notificationChannels: parsed.body.notifications,
|
|
6429
6450
|
createdBy
|
|
6430
6451
|
});
|
|
6452
|
+
const notifications = parsed.body.notifications;
|
|
6453
|
+
if (notifications?.length && request.status === "pending") {
|
|
6454
|
+
dispatchApprovalNotifications({
|
|
6455
|
+
requestId: request.id,
|
|
6456
|
+
title: request.title,
|
|
6457
|
+
questions: parsed.body.questions,
|
|
6458
|
+
timeoutSeconds: parsed.body.timeoutSeconds,
|
|
6459
|
+
notifications
|
|
6460
|
+
}).catch((err) => {
|
|
6461
|
+
console.error("[approval-requests] Unexpected error dispatching notifications:", scrubSecrets(err instanceof Error ? err.message : String(err)));
|
|
6462
|
+
});
|
|
6463
|
+
}
|
|
6431
6464
|
createRoute.respond(res, 201, {
|
|
6432
6465
|
approvalRequest: await toApprovalRequestResponse(request)
|
|
6433
6466
|
});
|
|
@@ -6456,7 +6489,8 @@ async function handleApprovalRequests(req, res, pathSegments, queryParams) {
|
|
|
6456
6489
|
}
|
|
6457
6490
|
return false;
|
|
6458
6491
|
}
|
|
6459
|
-
|
|
6492
|
+
var SLACK_NOTIFICATION_REFUSED = "Slack notifications require lead privileges (integration.slack.post). Create the request without them, or ask the lead to post the link.";
|
|
6493
|
+
async function approvalCallerPrincipal(req) {
|
|
6460
6494
|
const auth = getRequestAuth(req);
|
|
6461
6495
|
if (auth?.kind === "user") {
|
|
6462
6496
|
return { principal: { kind: "user", userId: auth.userId }, resolvedBy: auth.userId };
|
|
@@ -28497,6 +28531,7 @@ init_zod();
|
|
|
28497
28531
|
var import_cron_parser = __toESM(require_dist2(), 1);
|
|
28498
28532
|
init_db3();
|
|
28499
28533
|
init_db2();
|
|
28534
|
+
init_rbac();
|
|
28500
28535
|
init_types();
|
|
28501
28536
|
var scheduleUpdateBodySchema = object2({
|
|
28502
28537
|
key: AssetKeySchema.optional(),
|
|
@@ -28649,6 +28684,7 @@ var updateSchedule = route({
|
|
|
28649
28684
|
responses: {
|
|
28650
28685
|
200: { description: "Schedule updated", schema: ScheduledTaskSchema.nullable() },
|
|
28651
28686
|
400: { description: "Validation error" },
|
|
28687
|
+
403: { description: "Deferral owned by another agent" },
|
|
28652
28688
|
404: { description: "Schedule not found" },
|
|
28653
28689
|
409: { description: "Duplicate name" }
|
|
28654
28690
|
}
|
|
@@ -28665,6 +28701,7 @@ var patchSchedule = route({
|
|
|
28665
28701
|
responses: {
|
|
28666
28702
|
200: { description: "Schedule patched", schema: ScheduledTaskSchema.nullable() },
|
|
28667
28703
|
400: { description: "Validation error" },
|
|
28704
|
+
403: { description: "Deferral owned by another agent" },
|
|
28668
28705
|
404: { description: "Schedule not found" },
|
|
28669
28706
|
409: { description: "Duplicate name" }
|
|
28670
28707
|
},
|
|
@@ -28936,6 +28973,18 @@ async function handleSchedules(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
28936
28973
|
jsonError(res, "Schedule not found", 404);
|
|
28937
28974
|
return true;
|
|
28938
28975
|
}
|
|
28976
|
+
if (existing.taskType === "deferred") {
|
|
28977
|
+
const principal = await agentFirstPrincipal(req, myAgentId);
|
|
28978
|
+
if (principal.kind === "agent" && !can({
|
|
28979
|
+
principal,
|
|
28980
|
+
verb: "schedule.deferral.update.any",
|
|
28981
|
+
resource: { kind: "owned", ownerAgentId: existing.createdByAgentId },
|
|
28982
|
+
source: "http"
|
|
28983
|
+
}).allow) {
|
|
28984
|
+
jsonError(res, `Schedule "${existing.name}" defers another agent's task. Only that agent or a lead can change it.`, 403);
|
|
28985
|
+
return true;
|
|
28986
|
+
}
|
|
28987
|
+
}
|
|
28939
28988
|
const agentChanged = parsed.body.targetAgentId !== undefined && parsed.body.targetAgentId !== existing.targetAgentId;
|
|
28940
28989
|
if (parsed.body.model !== undefined || parsed.body.modelTier !== undefined) {
|
|
28941
28990
|
const normalizedModel = splitLegacyModelAlias({
|
|
@@ -32377,7 +32426,7 @@ async function handleScripts(req, res, pathSegments, queryParams, agentId) {
|
|
|
32377
32426
|
const startedAt = new Date().toISOString();
|
|
32378
32427
|
const runStartTouch = namedScript?.isScratch ? await touchScratchScriptLastUsed(namedScript.id) : null;
|
|
32379
32428
|
const credentials = await buildScriptCredentialBindingsWithFailures({ agentId: agent.id });
|
|
32380
|
-
const output = await
|
|
32429
|
+
const output = await runScriptWithRunCredential({
|
|
32381
32430
|
source,
|
|
32382
32431
|
args: parsed.body.args,
|
|
32383
32432
|
fsMode,
|
|
@@ -33344,7 +33393,8 @@ var SessionTreeResponseSchema = object2({
|
|
|
33344
33393
|
inbox: SessionSectionCountsSchema,
|
|
33345
33394
|
later: SessionSectionCountsSchema,
|
|
33346
33395
|
done: SessionSectionCountsSchema,
|
|
33347
|
-
noGroup: SessionSectionCountsSchema
|
|
33396
|
+
noGroup: SessionSectionCountsSchema,
|
|
33397
|
+
sources: array2(object2({ source: string2(), total: number2().int() })).describe("Each root source in this view with its session count, hidden sources included.")
|
|
33348
33398
|
});
|
|
33349
33399
|
var SessionApprovalSchema = object2({
|
|
33350
33400
|
id: string2(),
|
|
@@ -33603,6 +33653,8 @@ async function handleAgentTokens(req, res, pathSegments, queryParams) {
|
|
|
33603
33653
|
revokeAgentTokenRoute.respond(res, 200, { revoked: await revokeAgentTokens(parsed.params.id) });
|
|
33604
33654
|
return true;
|
|
33605
33655
|
}
|
|
33656
|
+
var SessionShowSchema = _enum2(["mine", "all"]).optional().describe("Sessions v2 view, for a user viewer with tree scope. mine (default): roots the user started from a human channel (not workflow, schedule, or system) plus sessions shared with the user. all: every tree session. Lists only: access is unchanged.");
|
|
33657
|
+
var SessionHideSourceSchema = string2().refine((value) => value.split(",").length <= 32, "hideSource takes at most 32 sources.").optional().transform((value) => value?.split(",").map((source) => source.trim()).filter(Boolean)).describe("Comma-separated root sources to leave out (the sessions v2 source filter), e.g. `slack,chat`.");
|
|
33606
33658
|
var listSessions = route({
|
|
33607
33659
|
method: "get",
|
|
33608
33660
|
path: "/api/sessions",
|
|
@@ -33624,7 +33676,9 @@ var listSessions = route({
|
|
|
33624
33676
|
status: _enum2(["running", "failed", "needs"]).optional(),
|
|
33625
33677
|
withUserId: string2().min(1).optional(),
|
|
33626
33678
|
fields: _enum2(["full", "slim"]).optional(),
|
|
33627
|
-
scope: _enum2(["mine", "shared", "tree"]).optional().describe("mine: owned sessions. shared: sessions shared with me. tree: Sessions that GET /api/session-tree counts: mine plus shared with me, no ownerless roots. A bypass actor sees every root with tree scope.")
|
|
33679
|
+
scope: _enum2(["mine", "shared", "tree"]).optional().describe("mine: owned sessions. shared: sessions shared with me. tree: Sessions that GET /api/session-tree counts: mine plus shared with me, no ownerless roots. A bypass actor sees every root with tree scope."),
|
|
33680
|
+
show: SessionShowSchema,
|
|
33681
|
+
hideSource: SessionHideSourceSchema
|
|
33628
33682
|
}),
|
|
33629
33683
|
responses: {
|
|
33630
33684
|
200: {
|
|
@@ -33646,12 +33700,41 @@ var sessionTree = route({
|
|
|
33646
33700
|
pattern: ["api", "session-tree"],
|
|
33647
33701
|
summary: "Get session groups and triage counts",
|
|
33648
33702
|
tags: ["Sessions"],
|
|
33703
|
+
query: object2({ show: SessionShowSchema, hideSource: SessionHideSourceSchema }),
|
|
33649
33704
|
responses: {
|
|
33650
33705
|
200: { description: "Visible groups and section counts", schema: SessionTreeResponseSchema },
|
|
33651
33706
|
401: { description: "Unauthorized" }
|
|
33652
33707
|
},
|
|
33653
33708
|
auth: { apiKey: true }
|
|
33654
33709
|
});
|
|
33710
|
+
var triageSessionListRoute = route({
|
|
33711
|
+
method: "post",
|
|
33712
|
+
path: "/api/session-triage",
|
|
33713
|
+
pattern: ["api", "session-triage"],
|
|
33714
|
+
summary: "Triage every session of one sidebar list",
|
|
33715
|
+
description: "The bulk bar's 'Select all N': Done, back to the Inbox, read, or unread for every session that one sessions v2 list shows the caller (the `GET /api/sessions?scope=tree` filters). Needs a picked user.",
|
|
33716
|
+
tags: ["Sessions"],
|
|
33717
|
+
body: object2({
|
|
33718
|
+
action: _enum2(["done", "inbox", "read", "unread"]),
|
|
33719
|
+
triage: _enum2(["inbox", "later", "done"]).optional(),
|
|
33720
|
+
noGroup: boolean().optional(),
|
|
33721
|
+
groupKey: SessionKeyFilterSchema.optional(),
|
|
33722
|
+
show: SessionShowSchema,
|
|
33723
|
+
hideSource: array2(string2().min(1)).max(32).optional()
|
|
33724
|
+
}).refine((body) => [body.triage, body.noGroup, body.groupKey].filter(Boolean).length === 1, {
|
|
33725
|
+
message: "Name exactly one list: triage, noGroup, or groupKey"
|
|
33726
|
+
}),
|
|
33727
|
+
responses: {
|
|
33728
|
+
200: {
|
|
33729
|
+
description: "The number of sessions written",
|
|
33730
|
+
schema: object2({ updated: number2().int() })
|
|
33731
|
+
},
|
|
33732
|
+
400: { description: "Validation error, or no picked user" },
|
|
33733
|
+
401: { description: "Unauthorized" }
|
|
33734
|
+
},
|
|
33735
|
+
auth: { apiKey: true },
|
|
33736
|
+
rbac: { ungated: "per-user inbox UI state, same posture as PATCH /api/inbox-state" }
|
|
33737
|
+
});
|
|
33655
33738
|
var SESSION_MOVE_LIMIT = 200;
|
|
33656
33739
|
var SESSION_MOVE_OWNER_ONLY = "Only the session owner can move this group";
|
|
33657
33740
|
var SESSION_MOVE_UNAVAILABLE = "Session not found or not accessible";
|
|
@@ -33905,6 +33988,7 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
33905
33988
|
}
|
|
33906
33989
|
const filterOpts = {
|
|
33907
33990
|
source: sources,
|
|
33991
|
+
hideSource: parsed.query.hideSource,
|
|
33908
33992
|
q: parsed.query.q,
|
|
33909
33993
|
requestedByUserId: parsed.query.requestedByUserId,
|
|
33910
33994
|
contextKeyPrefix: parsed.query.contextKeyPrefix,
|
|
@@ -33916,6 +34000,7 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
33916
34000
|
withUserId: parsed.query.withUserId,
|
|
33917
34001
|
now: new Date().toISOString(),
|
|
33918
34002
|
tree: parsed.query.scope === "tree",
|
|
34003
|
+
mine: parsed.query.scope === "tree" && parsed.query.show !== "all",
|
|
33919
34004
|
...actor.kind === "user" ? {
|
|
33920
34005
|
viewer: {
|
|
33921
34006
|
userId: actor.userId,
|
|
@@ -33942,7 +34027,25 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
|
|
|
33942
34027
|
const parsed = await sessionTree.parse(req, res, pathSegments, queryParams);
|
|
33943
34028
|
if (!parsed)
|
|
33944
34029
|
return true;
|
|
33945
|
-
|
|
34030
|
+
const actor = await resolveSessionActor2(req, myAgentId);
|
|
34031
|
+
sessionTree.respond(res, 200, await getSessionTree(actor, undefined, {
|
|
34032
|
+
mine: parsed.query.show !== "all",
|
|
34033
|
+
hideSource: parsed.query.hideSource
|
|
34034
|
+
}));
|
|
34035
|
+
return true;
|
|
34036
|
+
}
|
|
34037
|
+
if (triageSessionListRoute.match(req.method, pathSegments)) {
|
|
34038
|
+
const parsed = await triageSessionListRoute.parse(req, res, pathSegments, queryParams);
|
|
34039
|
+
if (!parsed)
|
|
34040
|
+
return true;
|
|
34041
|
+
const actor = await resolveSessionActor2(req, myAgentId);
|
|
34042
|
+
if (actor.kind !== "user" || !actor.userId) {
|
|
34043
|
+
jsonError(res, "Pick a user to triage sessions", 400);
|
|
34044
|
+
return true;
|
|
34045
|
+
}
|
|
34046
|
+
const { action, show, ...list } = parsed.body;
|
|
34047
|
+
const updated = await triageSessionList(actor.userId, { ...list, mine: show !== "all" }, action);
|
|
34048
|
+
triageSessionListRoute.respond(res, 200, { updated });
|
|
33946
34049
|
return true;
|
|
33947
34050
|
}
|
|
33948
34051
|
if (moveSessions.match(req.method, pathSegments)) {
|
|
@@ -36527,9 +36630,182 @@ async function handleTrackers(req, res, pathSegments) {
|
|
|
36527
36630
|
return await handleLinearTracker(req, res, pathSegments);
|
|
36528
36631
|
}
|
|
36529
36632
|
|
|
36633
|
+
// src/http/user-roles.ts
|
|
36634
|
+
init_zod();
|
|
36635
|
+
init_db3();
|
|
36636
|
+
init_rbac_roles();
|
|
36637
|
+
init_users();
|
|
36638
|
+
init_rbac();
|
|
36639
|
+
init_types();
|
|
36640
|
+
init_request_auth_context();
|
|
36641
|
+
|
|
36642
|
+
// src/http/operator-actor.ts
|
|
36643
|
+
init_users();
|
|
36644
|
+
init_api_key();
|
|
36645
|
+
init_request_auth_context();
|
|
36646
|
+
function extractBearer2(req) {
|
|
36647
|
+
const raw = req.headers.authorization;
|
|
36648
|
+
const header = Array.isArray(raw) ? raw[0] : raw;
|
|
36649
|
+
if (!header || !header.startsWith("Bearer "))
|
|
36650
|
+
return null;
|
|
36651
|
+
return header.slice(7);
|
|
36652
|
+
}
|
|
36653
|
+
function getOperatorActor(req, res) {
|
|
36654
|
+
const auth = getRequestAuth(req);
|
|
36655
|
+
if (auth?.kind === "user") {
|
|
36656
|
+
return { kind: "user", id: auth.userId };
|
|
36657
|
+
}
|
|
36658
|
+
if (auth?.kind === "operator") {
|
|
36659
|
+
return { kind: "operator", id: auth.fingerprint };
|
|
36660
|
+
}
|
|
36661
|
+
if (auth?.kind === "guest") {
|
|
36662
|
+
jsonError(res, "Forbidden", 403);
|
|
36663
|
+
return null;
|
|
36664
|
+
}
|
|
36665
|
+
const rawKey = extractBearer2(req);
|
|
36666
|
+
const swarmKey = getApiKey();
|
|
36667
|
+
if (!swarmKey) {
|
|
36668
|
+
return { kind: "operator", id: fingerprintApiKey("") };
|
|
36669
|
+
}
|
|
36670
|
+
if (!rawKey || rawKey !== swarmKey) {
|
|
36671
|
+
jsonError(res, "Unauthorized", 401);
|
|
36672
|
+
return null;
|
|
36673
|
+
}
|
|
36674
|
+
return { kind: "operator", id: fingerprintApiKey(rawKey) };
|
|
36675
|
+
}
|
|
36676
|
+
|
|
36677
|
+
// src/http/user-roles.ts
|
|
36678
|
+
var listRolesRoute = route({
|
|
36679
|
+
method: "get",
|
|
36680
|
+
path: "/api/rbac/roles",
|
|
36681
|
+
pattern: ["api", "rbac", "roles"],
|
|
36682
|
+
operationId: "rbac_listRoles",
|
|
36683
|
+
summary: "List RBAC roles with their verbs",
|
|
36684
|
+
tags: ["Users"],
|
|
36685
|
+
responses: {
|
|
36686
|
+
200: { description: "Role catalog", schema: object2({ roles: array2(RbacRoleSchema) }) }
|
|
36687
|
+
}
|
|
36688
|
+
});
|
|
36689
|
+
var getUserRolesRoute = route({
|
|
36690
|
+
method: "get",
|
|
36691
|
+
path: "/api/users/{id}/roles",
|
|
36692
|
+
pattern: ["api", "users", null, "roles"],
|
|
36693
|
+
operationId: "users_getRbacRoles",
|
|
36694
|
+
summary: "Get a user's RBAC roles",
|
|
36695
|
+
tags: ["Users"],
|
|
36696
|
+
params: object2({ id: string2().min(1) }),
|
|
36697
|
+
responses: {
|
|
36698
|
+
200: { description: "The user's roles", schema: UserRbacRolesSchema },
|
|
36699
|
+
404: { description: "User not found" }
|
|
36700
|
+
}
|
|
36701
|
+
});
|
|
36702
|
+
var setUserRolesRoute = route({
|
|
36703
|
+
method: "put",
|
|
36704
|
+
path: "/api/users/{id}/roles",
|
|
36705
|
+
pattern: ["api", "users", null, "roles"],
|
|
36706
|
+
operationId: "users_setRbacRoles",
|
|
36707
|
+
summary: "Set a user's RBAC roles",
|
|
36708
|
+
description: `Replaces the user's roles. The set holds exactly one of ${PRIMARY_ROLE_NAMES2.join(", ")} plus any extra roles. Demoting a user below admin removes the ability to answer approval requests, even when the user is listed as an approver. Fails with 409 when it would leave no active admin.`,
|
|
36709
|
+
tags: ["Users"],
|
|
36710
|
+
params: object2({ id: string2().min(1) }),
|
|
36711
|
+
body: object2({ roles: array2(string2().min(1)).min(1) }).strict(),
|
|
36712
|
+
responses: {
|
|
36713
|
+
200: { description: "The user's roles after the change", schema: UserRbacRolesSchema },
|
|
36714
|
+
400: { description: "Invalid role set" },
|
|
36715
|
+
403: { description: "Not allowed to change roles" },
|
|
36716
|
+
404: { description: "User not found" },
|
|
36717
|
+
409: { description: "Would leave no active admin" }
|
|
36718
|
+
},
|
|
36719
|
+
rbac: { permission: "user.role.manage" }
|
|
36720
|
+
});
|
|
36721
|
+
async function composeRoles(userId) {
|
|
36722
|
+
const [catalog, held] = await Promise.all([listRbacRoles2(), listUserRoles2(userId)]);
|
|
36723
|
+
const names = new Set(held.map((role) => role.name));
|
|
36724
|
+
return { userId, roles: catalog.filter((role) => names.has(role.name)) };
|
|
36725
|
+
}
|
|
36726
|
+
async function ensureRoleManager(req, res) {
|
|
36727
|
+
if (rejectGuest(req, res))
|
|
36728
|
+
return false;
|
|
36729
|
+
const auth = getRequestAuth(req);
|
|
36730
|
+
if (auth?.kind !== "operator" && auth?.kind !== "user") {
|
|
36731
|
+
jsonError(res, "Role changes require operator or user credentials", 403);
|
|
36732
|
+
return false;
|
|
36733
|
+
}
|
|
36734
|
+
const header = req.headers["x-agent-id"];
|
|
36735
|
+
const decision = can({
|
|
36736
|
+
principal: await agentFirstPrincipal(req, Array.isArray(header) ? header[0] : header),
|
|
36737
|
+
verb: "user.role.manage",
|
|
36738
|
+
resource: { kind: "none" },
|
|
36739
|
+
source: "http"
|
|
36740
|
+
});
|
|
36741
|
+
if (!decision.allow) {
|
|
36742
|
+
jsonError(res, decision.reason, 403);
|
|
36743
|
+
return false;
|
|
36744
|
+
}
|
|
36745
|
+
if (auth.kind === "user" && isRbacEnabled() && !(await getUserGrant2(auth.userId)).grantsAll) {
|
|
36746
|
+
jsonError(res, "Role changes require a grant-all role", 403);
|
|
36747
|
+
return false;
|
|
36748
|
+
}
|
|
36749
|
+
return true;
|
|
36750
|
+
}
|
|
36751
|
+
async function handleUserRoles(req, res, pathSegments, queryParams) {
|
|
36752
|
+
if (listRolesRoute.match(req.method, pathSegments)) {
|
|
36753
|
+
if (rejectGuest(req, res))
|
|
36754
|
+
return true;
|
|
36755
|
+
listRolesRoute.respond(res, 200, { roles: await listRbacRoles2() });
|
|
36756
|
+
return true;
|
|
36757
|
+
}
|
|
36758
|
+
if (getUserRolesRoute.match(req.method, pathSegments)) {
|
|
36759
|
+
if (rejectGuest(req, res))
|
|
36760
|
+
return true;
|
|
36761
|
+
const parsed = await getUserRolesRoute.parse(req, res, pathSegments, queryParams);
|
|
36762
|
+
if (!parsed)
|
|
36763
|
+
return true;
|
|
36764
|
+
if (!await getUserById2(parsed.params.id)) {
|
|
36765
|
+
jsonError(res, "User not found", 404);
|
|
36766
|
+
return true;
|
|
36767
|
+
}
|
|
36768
|
+
getUserRolesRoute.respond(res, 200, await composeRoles(parsed.params.id));
|
|
36769
|
+
return true;
|
|
36770
|
+
}
|
|
36771
|
+
if (setUserRolesRoute.match(req.method, pathSegments)) {
|
|
36772
|
+
const parsed = await setUserRolesRoute.parse(req, res, pathSegments, queryParams);
|
|
36773
|
+
if (!parsed)
|
|
36774
|
+
return true;
|
|
36775
|
+
if (!await ensureRoleManager(req, res))
|
|
36776
|
+
return true;
|
|
36777
|
+
const actor = getOperatorActor(req, res);
|
|
36778
|
+
if (!actor)
|
|
36779
|
+
return true;
|
|
36780
|
+
const userId = parsed.params.id;
|
|
36781
|
+
if (!await getUserById2(userId)) {
|
|
36782
|
+
jsonError(res, "User not found", 404);
|
|
36783
|
+
return true;
|
|
36784
|
+
}
|
|
36785
|
+
try {
|
|
36786
|
+
const { before, after } = await setUserRoles2(userId, parsed.body.roles, actor.kind === "user" ? actor.id : null);
|
|
36787
|
+
await recordIdentityEvent(userId, "profile_changed", actor, { rbacRoles: before }, { rbacRoles: after });
|
|
36788
|
+
} catch (err) {
|
|
36789
|
+
if (err instanceof LastAdminError2) {
|
|
36790
|
+
jsonError(res, "last_admin", 409);
|
|
36791
|
+
return true;
|
|
36792
|
+
}
|
|
36793
|
+
if (err instanceof InvalidRoleSetError2) {
|
|
36794
|
+
jsonError(res, err.message, 400);
|
|
36795
|
+
return true;
|
|
36796
|
+
}
|
|
36797
|
+
throw err;
|
|
36798
|
+
}
|
|
36799
|
+
setUserRolesRoute.respond(res, 200, await composeRoles(userId));
|
|
36800
|
+
return true;
|
|
36801
|
+
}
|
|
36802
|
+
return false;
|
|
36803
|
+
}
|
|
36804
|
+
|
|
36530
36805
|
// src/http/users.ts
|
|
36531
36806
|
init_zod();
|
|
36532
36807
|
init_db3();
|
|
36808
|
+
init_rbac_roles();
|
|
36533
36809
|
init_users();
|
|
36534
36810
|
init_types();
|
|
36535
36811
|
init_request_auth_context();
|
|
@@ -36600,41 +36876,6 @@ function createIpRateLimiter(options) {
|
|
|
36600
36876
|
};
|
|
36601
36877
|
}
|
|
36602
36878
|
|
|
36603
|
-
// src/http/operator-actor.ts
|
|
36604
|
-
init_users();
|
|
36605
|
-
init_api_key();
|
|
36606
|
-
init_request_auth_context();
|
|
36607
|
-
function extractBearer2(req) {
|
|
36608
|
-
const raw = req.headers.authorization;
|
|
36609
|
-
const header = Array.isArray(raw) ? raw[0] : raw;
|
|
36610
|
-
if (!header || !header.startsWith("Bearer "))
|
|
36611
|
-
return null;
|
|
36612
|
-
return header.slice(7);
|
|
36613
|
-
}
|
|
36614
|
-
function getOperatorActor(req, res) {
|
|
36615
|
-
const auth = getRequestAuth(req);
|
|
36616
|
-
if (auth?.kind === "user") {
|
|
36617
|
-
return { kind: "user", id: auth.userId };
|
|
36618
|
-
}
|
|
36619
|
-
if (auth?.kind === "operator") {
|
|
36620
|
-
return { kind: "operator", id: auth.fingerprint };
|
|
36621
|
-
}
|
|
36622
|
-
if (auth?.kind === "guest") {
|
|
36623
|
-
jsonError(res, "Forbidden", 403);
|
|
36624
|
-
return null;
|
|
36625
|
-
}
|
|
36626
|
-
const rawKey = extractBearer2(req);
|
|
36627
|
-
const swarmKey = getApiKey();
|
|
36628
|
-
if (!swarmKey) {
|
|
36629
|
-
return { kind: "operator", id: fingerprintApiKey("") };
|
|
36630
|
-
}
|
|
36631
|
-
if (!rawKey || rawKey !== swarmKey) {
|
|
36632
|
-
jsonError(res, "Unauthorized", 401);
|
|
36633
|
-
return null;
|
|
36634
|
-
}
|
|
36635
|
-
return { kind: "operator", id: fingerprintApiKey(rawKey) };
|
|
36636
|
-
}
|
|
36637
|
-
|
|
36638
36879
|
// src/http/users.ts
|
|
36639
36880
|
async function composeUser(userId, recentEventLimit = 5) {
|
|
36640
36881
|
const user = await getUserById2(userId);
|
|
@@ -36990,7 +37231,8 @@ var mergeUsersRoute = route({
|
|
|
36990
37231
|
},
|
|
36991
37232
|
400: { description: "Validation error (e.g. target == source)" },
|
|
36992
37233
|
401: { description: "Unauthorized" },
|
|
36993
|
-
404: { description: "Target or source user not found" }
|
|
37234
|
+
404: { description: "Target or source user not found" },
|
|
37235
|
+
409: { description: "Source is the last active admin (last_admin)" }
|
|
36994
37236
|
},
|
|
36995
37237
|
auth: { apiKey: true }
|
|
36996
37238
|
});
|
|
@@ -37472,6 +37714,7 @@ async function handleUsers(req, res, pathSegments, queryParams) {
|
|
|
37472
37714
|
await recordIdentityEvent(targetId, "email_added", actor, null, { email: alias });
|
|
37473
37715
|
}
|
|
37474
37716
|
}
|
|
37717
|
+
await assertNotLastAdmin2(sourceId);
|
|
37475
37718
|
await deleteUser2(sourceId, targetId);
|
|
37476
37719
|
const targetAfter = await composeUser(targetId);
|
|
37477
37720
|
await recordIdentityEvent(targetId, "manual_merge", actor, targetBefore, {
|
|
@@ -37486,6 +37729,10 @@ async function handleUsers(req, res, pathSegments, queryParams) {
|
|
|
37486
37729
|
});
|
|
37487
37730
|
mergeUsersRoute.respond(res, 200, { user: mergedUser });
|
|
37488
37731
|
} catch (err) {
|
|
37732
|
+
if (err instanceof LastAdminError2) {
|
|
37733
|
+
jsonError(res, "last_admin", 409);
|
|
37734
|
+
return true;
|
|
37735
|
+
}
|
|
37489
37736
|
jsonError(res, err instanceof Error ? err.message : "Failed to merge users", 500);
|
|
37490
37737
|
}
|
|
37491
37738
|
return true;
|
|
@@ -39619,7 +39866,7 @@ async function handleX(req, res, pathSegments) {
|
|
|
39619
39866
|
const credentials = await buildScriptCredentialBindingsWithFailures({
|
|
39620
39867
|
agentId: endpoint.agentId
|
|
39621
39868
|
});
|
|
39622
|
-
const output = await
|
|
39869
|
+
const output = await runScriptWithRunCredential({
|
|
39623
39870
|
source: script.source,
|
|
39624
39871
|
args: args ?? null,
|
|
39625
39872
|
fsMode: "none",
|
|
@@ -39833,6 +40080,7 @@ var httpServer = createHttpServer(async (req, res) => {
|
|
|
39833
40080
|
() => handleRuntimePools(req, res, pathSegments, queryParams, myAgentId),
|
|
39834
40081
|
() => handleExtensions(req, res, pathSegments, queryParams, myAgentId),
|
|
39835
40082
|
() => handleFavorites(req, res, pathSegments, queryParams, myAgentId),
|
|
40083
|
+
() => handleUserRoles(req, res, pathSegments, queryParams),
|
|
39836
40084
|
() => handleUsers(req, res, pathSegments, queryParams),
|
|
39837
40085
|
() => handleSessions(req, res, pathSegments, queryParams, myAgentId),
|
|
39838
40086
|
() => handleInboxState(req, res, pathSegments, queryParams),
|
|
@@ -39870,7 +40118,7 @@ var httpServer = createHttpServer(async (req, res) => {
|
|
|
39870
40118
|
});
|
|
39871
40119
|
});
|
|
39872
40120
|
var detachRealtime = attachRealtimeTransport(httpServer);
|
|
39873
|
-
var { attachControllerTransport } = await import("./controllers-connect-
|
|
40121
|
+
var { attachControllerTransport } = await import("./controllers-connect-jzx7t4bn.js");
|
|
39874
40122
|
var detachControllers = attachControllerTransport(httpServer);
|
|
39875
40123
|
var stopWorkerNudges = startWorkerNudgeListener();
|
|
39876
40124
|
var stopRoomDeletion = realtimeBus.subscribe("room:namespace-deleted", (namespace) => {
|
|
@@ -39899,7 +40147,7 @@ async function shutdown() {
|
|
|
39899
40147
|
sessionsProcessed: getServerSessionsProcessed()
|
|
39900
40148
|
});
|
|
39901
40149
|
if (hasCapability("scheduling")) {
|
|
39902
|
-
const { stopScheduler } = await import("./index-
|
|
40150
|
+
const { stopScheduler } = await import("./index-1cscynkb.js");
|
|
39903
40151
|
stopScheduler();
|
|
39904
40152
|
}
|
|
39905
40153
|
stopHeartbeat2();
|
|
@@ -39911,7 +40159,7 @@ async function shutdown() {
|
|
|
39911
40159
|
await stopSlackApp2();
|
|
39912
40160
|
await stopChatSdk();
|
|
39913
40161
|
if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
|
|
39914
|
-
const { stopOAuthKeepalive } = await import("./keepalive-
|
|
40162
|
+
const { stopOAuthKeepalive } = await import("./keepalive-a9srcphj.js");
|
|
39915
40163
|
await stopOAuthKeepalive();
|
|
39916
40164
|
}
|
|
39917
40165
|
stopOAuthPendingGc();
|
|
@@ -39991,21 +40239,21 @@ try {
|
|
|
39991
40239
|
console.warn("[startup] CAPABILITIES upgrade seed failed (non-fatal):", err);
|
|
39992
40240
|
}
|
|
39993
40241
|
try {
|
|
39994
|
-
const { ensurePricingSeeded } = await import("./boot-seeds-
|
|
40242
|
+
const { ensurePricingSeeded } = await import("./boot-seeds-0n82qc7q.js");
|
|
39995
40243
|
ensurePricingSeeded();
|
|
39996
|
-
const { startPricingRefreshLoop } = await import("./pricing-refresh-
|
|
40244
|
+
const { startPricingRefreshLoop } = await import("./pricing-refresh-t27anv4z.js");
|
|
39997
40245
|
startPricingRefreshLoop();
|
|
39998
40246
|
} catch (err) {
|
|
39999
40247
|
console.error("[startup] Failed to seed pricing rows:", err);
|
|
40000
40248
|
}
|
|
40001
40249
|
try {
|
|
40002
|
-
const { ensureModelProfilesSeeded } = await import("./boot-seeds-
|
|
40250
|
+
const { ensureModelProfilesSeeded } = await import("./boot-seeds-0n82qc7q.js");
|
|
40003
40251
|
await ensureModelProfilesSeeded();
|
|
40004
40252
|
} catch (err) {
|
|
40005
40253
|
console.error("[startup] Failed to seed model profiles:", err);
|
|
40006
40254
|
}
|
|
40007
40255
|
try {
|
|
40008
|
-
const { ensureRbacSeeded } = await import("./boot-seeds-
|
|
40256
|
+
const { ensureRbacSeeded } = await import("./boot-seeds-0n82qc7q.js");
|
|
40009
40257
|
ensureRbacSeeded();
|
|
40010
40258
|
} catch (err) {
|
|
40011
40259
|
console.error("[startup] Failed to sync RBAC seed rows:", err);
|
|
@@ -40013,7 +40261,7 @@ try {
|
|
|
40013
40261
|
throw err;
|
|
40014
40262
|
}
|
|
40015
40263
|
try {
|
|
40016
|
-
const { runAllSeeders } = await import("./index-
|
|
40264
|
+
const { runAllSeeders } = await import("./index-06qkmcx6.js");
|
|
40017
40265
|
await runAllSeeders({ scriptEmbeddingMode: "skip" });
|
|
40018
40266
|
} catch (err) {
|
|
40019
40267
|
console.error("[startup] Failed to seed built-in entities:", err);
|
|
@@ -40076,39 +40324,39 @@ httpServer.listen(port, async () => {
|
|
|
40076
40324
|
await initWorkflows2();
|
|
40077
40325
|
await startScriptRunSupervisor(getMcpBaseUrl());
|
|
40078
40326
|
if (hasCapability("scheduling")) {
|
|
40079
|
-
const { startScheduler } = await import("./index-
|
|
40080
|
-
const { getExecutorRegistry } = await import("./index-
|
|
40327
|
+
const { startScheduler } = await import("./index-1cscynkb.js");
|
|
40328
|
+
const { getExecutorRegistry } = await import("./index-r70q0xjx.js");
|
|
40081
40329
|
const intervalMs = Number(process.env.SCHEDULER_INTERVAL_MS) || 1e4;
|
|
40082
40330
|
startScheduler(getExecutorRegistry(), intervalMs, {
|
|
40083
40331
|
runId: globalState.__runId
|
|
40084
40332
|
});
|
|
40085
40333
|
}
|
|
40086
40334
|
if (!isEnvFlagEnabled("HEARTBEAT_DISABLE", false)) {
|
|
40087
|
-
const { startHeartbeat } = await import("./index-
|
|
40335
|
+
const { startHeartbeat } = await import("./index-s193j5fh.js");
|
|
40088
40336
|
const heartbeatMs = Number(process.env.HEARTBEAT_INTERVAL_MS) || 90000;
|
|
40089
40337
|
startHeartbeat(heartbeatMs);
|
|
40090
40338
|
}
|
|
40091
40339
|
startPoolRouting();
|
|
40092
40340
|
startRuntimeSupervisor();
|
|
40093
40341
|
if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
|
|
40094
|
-
const { startOAuthKeepalive } = await import("./keepalive-
|
|
40342
|
+
const { startOAuthKeepalive } = await import("./keepalive-a9srcphj.js");
|
|
40095
40343
|
startOAuthKeepalive();
|
|
40096
40344
|
}
|
|
40097
40345
|
if (process.env.OAUTH_REFRESH_SWEEP_DISABLE !== "true") {
|
|
40098
|
-
const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-
|
|
40346
|
+
const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-b65jcyw2.js");
|
|
40099
40347
|
startOAuthRefreshSweep();
|
|
40100
40348
|
}
|
|
40101
40349
|
startOAuthPendingGc();
|
|
40102
40350
|
await startMemoryGc();
|
|
40103
40351
|
await startDbRetention();
|
|
40104
40352
|
startHumanFreeDrain();
|
|
40105
|
-
import("./boot-reembed-
|
|
40353
|
+
import("./boot-reembed-r3e808ky.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
|
|
40106
40354
|
console.error("[boot-reembed] startup backfill failed (non-fatal):", err);
|
|
40107
40355
|
});
|
|
40108
|
-
import("./boot-reembed-
|
|
40356
|
+
import("./boot-reembed-tgrfy27t.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
|
|
40109
40357
|
console.error("[boot-reembed-scripts] startup backfill failed (non-fatal):", err);
|
|
40110
40358
|
});
|
|
40111
|
-
import("./boot-scrub-sweep-
|
|
40359
|
+
import("./boot-scrub-sweep-masdwxkm.js").then(({ runBootScrubSweep }) => runBootScrubSweep()).catch((err) => {
|
|
40112
40360
|
console.error("[boot-scrub-sweep] startup scrub failed (non-fatal):", err);
|
|
40113
40361
|
});
|
|
40114
40362
|
}).on("error", (err) => {
|