@runeya/runeya 2.0.148 → 2.0.149
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/agent/index.js +29 -2
- package/agent/index.js.map +1 -1
- package/agent-manager-5VR5TDBZ.js +13 -0
- package/chat-EMWEVXGR.js +28 -0
- package/{chunk-4LJQIQMN.js → chunk-3RCVOPTL.js} +2 -2
- package/{chunk-WDHLEO5S.js → chunk-64FCYYAB.js} +5 -5
- package/{chunk-7QXP4FXD.js → chunk-76D52RTB.js} +6 -6
- package/{chunk-DFPZ4MTI.js → chunk-AZSHM3NM.js} +4 -4
- package/{chunk-4D3GCBPO.js → chunk-HRNYFWGP.js} +5 -5
- package/{chunk-MZSDTA4A.js → chunk-LJ7KLYFQ.js} +59 -3
- package/chunk-LJ7KLYFQ.js.map +1 -0
- package/{chunk-6IBPK6UE.js → chunk-OPVJAPUF.js} +2 -2
- package/{chunk-VPSQJOSN.js → chunk-SHSWOE5S.js} +2 -2
- package/{chunk-57P45FNY.js → chunk-T6Y5KICH.js} +2 -2
- package/{chunk-5XG3X2TM.js → chunk-UEK7QFWY.js} +6 -6
- package/{chunk-JNK6H5KH.js → chunk-UJ2OHNEN.js} +12 -12
- package/{chunk-2NE52CL5.js → chunk-XQGABRZY.js} +23 -22
- package/chunk-XQGABRZY.js.map +1 -0
- package/{chunk-NPMSBYXC.js → chunk-ZVXPGKK5.js} +4 -4
- package/{companion-XKMNRIJB.js → companion-H24L2MGY.js} +9 -9
- package/{desktop-installer-page-I5FHFDES.js → desktop-installer-page-V2NXWT43.js} +3 -3
- package/{desktop-launcher-GD4QPM66.js → desktop-launcher-46OJ5NAA.js} +3 -3
- package/{environment-resolver-ZDTF3MHI.js → environment-resolver-SY36Q67E.js} +6 -6
- package/{external-NMKQPROK.js → external-NPJBOEYV.js} +3 -3
- package/index.js +12 -12
- package/{install-gate-PWPGC63Z.js → install-gate-6KHRGTTC.js} +2 -2
- package/mcp-server/external.js +29 -2
- package/mcp-server/external.js.map +1 -1
- package/mcp-server/index.js +29 -2
- package/mcp-server/index.js.map +1 -1
- package/package.json +1 -1
- package/{project-store-FLXTAD3J.js → project-store-BYAE4SVZ.js} +7 -7
- package/settings-manager-GIRMJQKL.js +10 -0
- package/{src-DCCEUWE6.js → src-AAOVGV5C.js} +6 -2
- package/{src-I5TPC6GW.js → src-OENXLZKQ.js} +1288 -240
- package/src-OENXLZKQ.js.map +1 -0
- package/{vault-resolver-E7KPKA5C.js → vault-resolver-B6BCVP47.js} +3 -3
- package/web/assets/{AgentScalarChatInterface.vue-DKBinB_l.js → AgentScalarChatInterface.vue-YCBDhPTj.js} +1 -1
- package/web/assets/{AgentTerminalPage-CixU7x6O.js → AgentTerminalPage-BSeo7WB7.js} +1 -1
- package/web/assets/AiChatModals-BgZ3L5A7.js +4 -0
- package/web/assets/AiChatModals-BmWxg-Sr.css +1 -0
- package/web/assets/{AppLayout-At9wk0sx.js → AppLayout-Ds1L1Mir.js} +1 -1
- package/web/assets/{AuditPage-BkqbHxjY.js → AuditPage-i2k_iiea.js} +1 -1
- package/web/assets/{CloudAccountPage-D5C2SCS9.js → CloudAccountPage-DjCOwzkz.js} +1 -1
- package/web/assets/{CloudMessagingPage-Bi57GGHO.js → CloudMessagingPage-D7Xde0YP.js} +1 -1
- package/web/assets/{DashboardPage-dEQop9ql.js → DashboardPage-CxmCDaFn.js} +1 -1
- package/web/assets/{DirectoryPickerDialog-DIMSeDhw.js → DirectoryPickerDialog-IXy2Cylp.js} +1 -1
- package/web/assets/{EditorIcon-W3Szca4J.js → EditorIcon-CcU8Z46_.js} +1 -1
- package/web/assets/{EnvironmentForm-C5emavNh.js → EnvironmentForm-B5S5hkZH.js} +1 -1
- package/web/assets/{EnvironmentFormPage-BIoy8fsW.js → EnvironmentFormPage-B68x1h6h.js} +1 -1
- package/web/assets/{EnvironmentListPage-BDYeh7XF.js → EnvironmentListPage-Cm85L1Cy.js} +1 -1
- package/web/assets/{FlagChip-DPtIBCjQ.js → FlagChip-maG1f7pl.js} +1 -1
- package/web/assets/KanbanBoardPage-Bb_8xU-I.css +1 -0
- package/web/assets/KanbanBoardPage-FlQC9xsU.js +4 -0
- package/web/assets/{KanbanListPage-DbXONxfC.js → KanbanListPage-Df4Z4Y8g.js} +1 -1
- package/web/assets/{LaunchProjectPage-Cg92hHwQ.js → LaunchProjectPage-B9s8MPOR.js} +1 -1
- package/web/assets/{LaunchServicesPage-CO8gOB9D.js → LaunchServicesPage-r43I_lWM.js} +1 -1
- package/web/assets/{LaunchShell-CDb21ihZ.js → LaunchShell-DtBjvLt-.js} +1 -1
- package/web/assets/{LogViewer-DsusKk2b.js → LogViewer-D2s-OyaX.js} +1 -1
- package/web/assets/{OrgKeyPrompt-CX9K7r9I.js → OrgKeyPrompt-DoIyrK0q.js} +1 -1
- package/web/assets/{ProcessControls-TEZutuxq.js → ProcessControls-CbBxTuHk.js} +1 -1
- package/web/assets/{ProcessDetailPage-Cj23FECq.js → ProcessDetailPage-BMTTtFB3.js} +1 -1
- package/web/assets/{ProcessMetrics-1P6iE2Il.js → ProcessMetrics-D-rQkzqK.js} +1 -1
- package/web/assets/{ProjectCreateDialog-D3aMWKfw.js → ProjectCreateDialog-DxsMuH_r.js} +1 -1
- package/web/assets/{ProjectLocationGate-DU0Jj8Nw.js → ProjectLocationGate-B_nzC6RT.js} +1 -1
- package/web/assets/{ProjectPublishDialog-D7sNKei3.js → ProjectPublishDialog-DpC8VIH7.js} +1 -1
- package/web/assets/{RandomJobTestPage-DQUMRHyf.js → RandomJobTestPage-Y77cBJR3.js} +1 -1
- package/web/assets/ScenarioEditorPage-BJaQ6iY1.js +14 -0
- package/web/assets/ScenarioEditorPage-BtKSjE2X.css +1 -0
- package/web/assets/{SendToChatDialog-BdWKjYmv.js → SendToChatDialog-CmsSEeFx.js} +1 -1
- package/web/assets/{ServiceControlsBar-B_J5m-Kc.js → ServiceControlsBar--VyfFz0G.js} +1 -1
- package/web/assets/{ServiceDetailPage-DhJcjFfY.js → ServiceDetailPage-C2Wavjac.js} +1 -1
- package/web/assets/{ServiceFormPage-fp8NCHSv.js → ServiceFormPage-BipwEBSc.js} +1 -1
- package/web/assets/{SettingsPage-NH2fQap4.css → SettingsPage-B951NEBm.css} +1 -1
- package/web/assets/{SettingsPage-s28BodWe.js → SettingsPage-Dul95AO1.js} +40 -40
- package/web/assets/{UnlockPage-BXXIPHW_.js → UnlockPage-DQBjRGHA.js} +1 -1
- package/web/assets/{VaultMigrationPage-BfNuKtkJ.js → VaultMigrationPage-kFPC7EU7.js} +1 -1
- package/web/assets/{VersionBadge-CW7czacg.js → VersionBadge-C0vc7eEJ.js} +1 -1
- package/web/assets/{WikiPage-BiwpCM3E.js → WikiPage-K6muETXh.js} +1 -1
- package/web/assets/{WikiView-CMch_06Z.js → WikiView-DZCXplGL.js} +1 -1
- package/web/assets/{add-scalar-classes-Ckanjq1h.js → add-scalar-classes-DT2FcA3X.js} +1 -1
- package/web/assets/{agent.store-piokQ9Dt.js → agent.store-DfMGUOUY.js} +1 -1
- package/web/assets/{auth-BT_jf-5e.js → auth-DSz8t1M_.js} +2 -2
- package/web/assets/{cloud-chat.store-CDKh4tIy.js → cloud-chat.store-WzurTZAg.js} +1 -1
- package/web/assets/{cloud-client-CzPdZLDq.js → cloud-client-BDyxOUmg.js} +2 -2
- package/web/assets/{cloud-session-BYfn6YM4.js → cloud-session-Chc6UTc4.js} +2 -2
- package/web/assets/composables-DguCUR3O.js +1 -0
- package/web/assets/dist-DTLmCuqE.js +1 -0
- package/web/assets/i18n-D3P4ZExP.js +1 -0
- package/web/assets/index-CnXzQkLZ.css +1 -0
- package/web/assets/{index-Ci2CNnit.js → index-CzGU0RCX.js} +6 -6
- package/web/assets/{modal-iRaP1izE.js → modal-B5BRgeuI.js} +1 -1
- package/web/assets/{notification.store-CvvuTBVz.js → notification.store-DEv3Bnn0.js} +1 -1
- package/web/assets/{project-launch.store-CTmbl8UY.js → project-launch.store-B5OL69Kk.js} +1 -1
- package/web/assets/{project.store-CNC6_4r4.js → project.store-CSuUie96.js} +1 -1
- package/web/assets/scenario.store-DdZT8Es0.js +7 -0
- package/web/assets/{service.store-B40U4QzI.js → service.store-CaPqbX9_.js} +1 -1
- package/web/assets/{settings-scope-CyWMCjRY.js → settings-scope-C4xy-LPU.js} +1 -1
- package/web/assets/{settings.store-Dw6bAoWE.js → settings.store-C7hBumKk.js} +1 -1
- package/web/assets/{src-DtCW_XCh.js → src-BlNaHk0H.js} +1 -1
- package/web/assets/src-D9TuCwn8.js +1960 -0
- package/web/assets/{src-DIBHat7I.js → src-DOcCcTQv.js} +1 -1
- package/web/assets/{src-CcvmgMAA.css → src-Dbg3CMY2.css} +1 -1
- package/web/assets/src-wUE_ebXd.css +1 -0
- package/web/assets/{trpc-BAZGRZBD.js → trpc-BVA95nUx.js} +3 -3
- package/web/assets/{useCloudOrg-EnXFBwt1.js → useCloudOrg-Cgj6WMpr.js} +1 -1
- package/web/assets/{useEnvVarAutocomplete-BxJh2Lw0.js → useEnvVarAutocomplete-DQdDjrRd.js} +1 -1
- package/web/assets/{useProjectCatalog-BrvUGv9A.js → useProjectCatalog-Dn7sBOL8.js} +1 -1
- package/web/assets/{useProjectCloudOrg-Czxlg00k.js → useProjectCloudOrg-r-olF7jJ.js} +1 -1
- package/web/assets/{useServiceUrlHost-Szz9y3rh.js → useServiceUrlHost-DP-_dCQG.js} +1 -1
- package/web/index.html +20 -20
- package/agent-manager-46C4NIQ2.js +0 -13
- package/chat-CMNDMXIP.js +0 -28
- package/chunk-2NE52CL5.js.map +0 -1
- package/chunk-MZSDTA4A.js.map +0 -1
- package/settings-manager-XPLBO35P.js +0 -10
- package/src-I5TPC6GW.js.map +0 -1
- package/web/assets/AiChatModals-BvGUd-QD.css +0 -1
- package/web/assets/AiChatModals-C-hXImkO.js +0 -4
- package/web/assets/KanbanBoardPage-BlCcjBwV.js +0 -4
- package/web/assets/KanbanBoardPage-eHmsrFGA.css +0 -1
- package/web/assets/ScenarioEditorPage-BSjSX4bw.css +0 -1
- package/web/assets/ScenarioEditorPage-DvCdcY9m.js +0 -14
- package/web/assets/composables-DiiOYol8.js +0 -1
- package/web/assets/dist-N4nrnbnA.js +0 -1
- package/web/assets/i18n-D0FT7rCj.js +0 -1
- package/web/assets/index-3LTzgeU-.css +0 -1
- package/web/assets/scenario.store-BIFQPXgl.js +0 -7
- package/web/assets/src-CrNi4Pjg.js +0 -1960
- package/web/assets/src-g1DRo8xZ.css +0 -1
- /package/{agent-manager-46C4NIQ2.js.map → agent-manager-5VR5TDBZ.js.map} +0 -0
- /package/{chat-CMNDMXIP.js.map → chat-EMWEVXGR.js.map} +0 -0
- /package/{chunk-4LJQIQMN.js.map → chunk-3RCVOPTL.js.map} +0 -0
- /package/{chunk-WDHLEO5S.js.map → chunk-64FCYYAB.js.map} +0 -0
- /package/{chunk-7QXP4FXD.js.map → chunk-76D52RTB.js.map} +0 -0
- /package/{chunk-DFPZ4MTI.js.map → chunk-AZSHM3NM.js.map} +0 -0
- /package/{chunk-4D3GCBPO.js.map → chunk-HRNYFWGP.js.map} +0 -0
- /package/{chunk-6IBPK6UE.js.map → chunk-OPVJAPUF.js.map} +0 -0
- /package/{chunk-VPSQJOSN.js.map → chunk-SHSWOE5S.js.map} +0 -0
- /package/{chunk-57P45FNY.js.map → chunk-T6Y5KICH.js.map} +0 -0
- /package/{chunk-5XG3X2TM.js.map → chunk-UEK7QFWY.js.map} +0 -0
- /package/{chunk-JNK6H5KH.js.map → chunk-UJ2OHNEN.js.map} +0 -0
- /package/{chunk-NPMSBYXC.js.map → chunk-ZVXPGKK5.js.map} +0 -0
- /package/{companion-XKMNRIJB.js.map → companion-H24L2MGY.js.map} +0 -0
- /package/{desktop-installer-page-I5FHFDES.js.map → desktop-installer-page-V2NXWT43.js.map} +0 -0
- /package/{desktop-launcher-GD4QPM66.js.map → desktop-launcher-46OJ5NAA.js.map} +0 -0
- /package/{environment-resolver-ZDTF3MHI.js.map → environment-resolver-SY36Q67E.js.map} +0 -0
- /package/{external-NMKQPROK.js.map → external-NPJBOEYV.js.map} +0 -0
- /package/{install-gate-PWPGC63Z.js.map → install-gate-6KHRGTTC.js.map} +0 -0
- /package/{project-store-FLXTAD3J.js.map → project-store-BYAE4SVZ.js.map} +0 -0
- /package/{settings-manager-XPLBO35P.js.map → settings-manager-GIRMJQKL.js.map} +0 -0
- /package/{src-DCCEUWE6.js.map → src-AAOVGV5C.js.map} +0 -0
- /package/{vault-resolver-E7KPKA5C.js.map → vault-resolver-B6BCVP47.js.map} +0 -0
|
@@ -67,7 +67,7 @@ import {
|
|
|
67
67
|
soleAccountScope,
|
|
68
68
|
startCliSession,
|
|
69
69
|
vaultOfProject
|
|
70
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-XQGABRZY.js";
|
|
71
71
|
import {
|
|
72
72
|
CONVERSATIONS_DIRNAME,
|
|
73
73
|
activeSessionRegistry,
|
|
@@ -87,20 +87,20 @@ import {
|
|
|
87
87
|
stopClaudeTranscriptWatcher,
|
|
88
88
|
stopCodexTranscriptWatcher,
|
|
89
89
|
verifyJwt
|
|
90
|
-
} from "./chunk-
|
|
91
|
-
import "./chunk-
|
|
90
|
+
} from "./chunk-UJ2OHNEN.js";
|
|
91
|
+
import "./chunk-OPVJAPUF.js";
|
|
92
92
|
import {
|
|
93
93
|
LocalProjectRefusedError,
|
|
94
94
|
ensureDataGitignore,
|
|
95
95
|
holdsRuneyaProject,
|
|
96
96
|
projectPathStore,
|
|
97
97
|
projectStore
|
|
98
|
-
} from "./chunk-
|
|
98
|
+
} from "./chunk-76D52RTB.js";
|
|
99
99
|
import {
|
|
100
100
|
environmentOverridesStore,
|
|
101
101
|
environmentResolver,
|
|
102
102
|
filterEnvForAi
|
|
103
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-64FCYYAB.js";
|
|
104
104
|
import {
|
|
105
105
|
agentManager,
|
|
106
106
|
agentSpawner,
|
|
@@ -112,10 +112,10 @@ import {
|
|
|
112
112
|
scheduleSelfRestart,
|
|
113
113
|
traefikManager,
|
|
114
114
|
unregisterInstance
|
|
115
|
-
} from "./chunk-
|
|
115
|
+
} from "./chunk-UEK7QFWY.js";
|
|
116
116
|
import {
|
|
117
117
|
serviceStore
|
|
118
|
-
} from "./chunk-
|
|
118
|
+
} from "./chunk-HRNYFWGP.js";
|
|
119
119
|
import {
|
|
120
120
|
clearDetached,
|
|
121
121
|
clearEncryptionKey,
|
|
@@ -143,7 +143,7 @@ import {
|
|
|
143
143
|
setEncryptionKeyInMemory,
|
|
144
144
|
setPendingLegacyKey,
|
|
145
145
|
stableEncryptValue
|
|
146
|
-
} from "./chunk-
|
|
146
|
+
} from "./chunk-AZSHM3NM.js";
|
|
147
147
|
import {
|
|
148
148
|
decryptValueWith,
|
|
149
149
|
encryptValueWith,
|
|
@@ -153,13 +153,13 @@ import {
|
|
|
153
153
|
} from "./chunk-OZBSOSAS.js";
|
|
154
154
|
import {
|
|
155
155
|
settingsManager
|
|
156
|
-
} from "./chunk-
|
|
156
|
+
} from "./chunk-ZVXPGKK5.js";
|
|
157
157
|
import {
|
|
158
158
|
atomicWriteSecure,
|
|
159
159
|
renameWithRetry,
|
|
160
160
|
resolveConversationRunDir,
|
|
161
161
|
sweepStaleTempFiles
|
|
162
|
-
} from "./chunk-
|
|
162
|
+
} from "./chunk-3RCVOPTL.js";
|
|
163
163
|
import "./chunk-MD3VW4HQ.js";
|
|
164
164
|
import {
|
|
165
165
|
allVaultRoots,
|
|
@@ -187,7 +187,7 @@ import {
|
|
|
187
187
|
rememberOrgName,
|
|
188
188
|
stampOrgCloud,
|
|
189
189
|
vaultFor
|
|
190
|
-
} from "./chunk-
|
|
190
|
+
} from "./chunk-SHSWOE5S.js";
|
|
191
191
|
import {
|
|
192
192
|
AGENT_LONG_FETCH_TIMEOUT,
|
|
193
193
|
AGENT_STOP_FETCH_TIMEOUT,
|
|
@@ -219,13 +219,14 @@ import {
|
|
|
219
219
|
deriveLauncherIdentity,
|
|
220
220
|
findUnresolvedReferences,
|
|
221
221
|
getCollection,
|
|
222
|
+
localizePreset,
|
|
222
223
|
nativeParsers,
|
|
223
224
|
primaryServiceLink,
|
|
224
225
|
readEntity,
|
|
225
226
|
serviceSlug,
|
|
226
227
|
suggestBuiltinReferences,
|
|
227
228
|
writeEntity
|
|
228
|
-
} from "./chunk-
|
|
229
|
+
} from "./chunk-LJ7KLYFQ.js";
|
|
229
230
|
|
|
230
231
|
// ../server/src/create-server.ts
|
|
231
232
|
import express from "express";
|
|
@@ -941,11 +942,11 @@ function addKey(buckets, from, target, key) {
|
|
|
941
942
|
}
|
|
942
943
|
function buildServiceGraph(input) {
|
|
943
944
|
const ambiguous = ambiguousServiceSlugs(input.services.map((s) => s.name));
|
|
944
|
-
const nodes = input.services.map((
|
|
945
|
-
const slug = serviceSlug(
|
|
945
|
+
const nodes = input.services.map((service2) => {
|
|
946
|
+
const slug = serviceSlug(service2.name);
|
|
946
947
|
return {
|
|
947
|
-
id:
|
|
948
|
-
name:
|
|
948
|
+
id: service2.id,
|
|
949
|
+
name: service2.name,
|
|
949
950
|
slug,
|
|
950
951
|
ambiguousSlug: ambiguous.has(slug)
|
|
951
952
|
};
|
|
@@ -956,14 +957,14 @@ function buildServiceGraph(input) {
|
|
|
956
957
|
}
|
|
957
958
|
const edgeBuckets = /* @__PURE__ */ new Map();
|
|
958
959
|
const danglingBuckets = /* @__PURE__ */ new Map();
|
|
959
|
-
for (const
|
|
960
|
-
const env2 = input.envByServiceId[
|
|
960
|
+
for (const service2 of input.services) {
|
|
961
|
+
const env2 = input.envByServiceId[service2.id] ?? {};
|
|
961
962
|
for (const [key, value] of Object.entries(env2)) {
|
|
962
963
|
for (const slug of crossServiceSlugsIn(value)) {
|
|
963
964
|
const target = bySlug.get(slug);
|
|
964
|
-
if (target ===
|
|
965
|
-
if (target) addKey(edgeBuckets,
|
|
966
|
-
else addKey(danglingBuckets,
|
|
965
|
+
if (target === service2.id) continue;
|
|
966
|
+
if (target) addKey(edgeBuckets, service2.id, target, key);
|
|
967
|
+
else addKey(danglingBuckets, service2.id, slug, key);
|
|
967
968
|
}
|
|
968
969
|
}
|
|
969
970
|
}
|
|
@@ -1153,18 +1154,18 @@ var projectRouter = router({
|
|
|
1153
1154
|
}
|
|
1154
1155
|
const runningServices = [];
|
|
1155
1156
|
for (const serviceId of project.serviceIds) {
|
|
1156
|
-
const
|
|
1157
|
-
if (!
|
|
1158
|
-
const agentStatus = agentManager.getStatus(
|
|
1157
|
+
const service2 = await serviceStore.get(serviceId);
|
|
1158
|
+
if (!service2 || !service2.agentId) continue;
|
|
1159
|
+
const agentStatus = agentManager.getStatus(service2.agentId);
|
|
1159
1160
|
if (!agentStatus?.connected) continue;
|
|
1160
1161
|
try {
|
|
1161
1162
|
const processStatus = await agentManager.agentQuery(
|
|
1162
|
-
|
|
1163
|
+
service2.agentId,
|
|
1163
1164
|
"process.get",
|
|
1164
1165
|
{ id: serviceId }
|
|
1165
1166
|
);
|
|
1166
1167
|
if (processStatus?.status === "running" || processStatus?.status === "starting") {
|
|
1167
|
-
runningServices.push({ serviceId, agentId:
|
|
1168
|
+
runningServices.push({ serviceId, agentId: service2.agentId });
|
|
1168
1169
|
}
|
|
1169
1170
|
} catch {
|
|
1170
1171
|
}
|
|
@@ -1177,18 +1178,18 @@ var projectRouter = router({
|
|
|
1177
1178
|
throw new TRPCError3({ code: "INTERNAL_SERVER_ERROR", message: "Failed to set active environment" });
|
|
1178
1179
|
}
|
|
1179
1180
|
for (const serviceId of project.serviceIds) {
|
|
1180
|
-
const
|
|
1181
|
-
if (!
|
|
1182
|
-
const agentStatus = agentManager.getStatus(
|
|
1181
|
+
const service2 = await serviceStore.get(serviceId);
|
|
1182
|
+
if (!service2 || !service2.agentId) continue;
|
|
1183
|
+
const agentStatus = agentManager.getStatus(service2.agentId);
|
|
1183
1184
|
if (!agentStatus?.connected) continue;
|
|
1184
|
-
let resolvedService =
|
|
1185
|
+
let resolvedService = service2;
|
|
1185
1186
|
try {
|
|
1186
1187
|
const resolved = await environmentResolver.resolveForService({
|
|
1187
|
-
serviceId:
|
|
1188
|
+
serviceId: service2.id,
|
|
1188
1189
|
activeEnvironmentId: input.environmentId
|
|
1189
1190
|
});
|
|
1190
1191
|
resolvedService = {
|
|
1191
|
-
...
|
|
1192
|
+
...service2,
|
|
1192
1193
|
env: { ...resolved.env },
|
|
1193
1194
|
envSecrets: [...resolved.envSecrets]
|
|
1194
1195
|
};
|
|
@@ -1198,9 +1199,9 @@ var projectRouter = router({
|
|
|
1198
1199
|
const wasRunning = runningServices.some((rs) => rs.serviceId === serviceId);
|
|
1199
1200
|
if (wasRunning) {
|
|
1200
1201
|
try {
|
|
1201
|
-
await agentManager.agentMutation(
|
|
1202
|
-
await agentManager.agentMutation(
|
|
1203
|
-
await agentManager.agentMutation(
|
|
1202
|
+
await agentManager.agentMutation(service2.agentId, "process.stop", { id: serviceId });
|
|
1203
|
+
await agentManager.agentMutation(service2.agentId, "process.deploy", resolvedService);
|
|
1204
|
+
await agentManager.agentMutation(service2.agentId, "process.start", { id: serviceId });
|
|
1204
1205
|
} catch (err) {
|
|
1205
1206
|
console.error("[project-router] Failed to restart service", serviceId + ":", err.message);
|
|
1206
1207
|
}
|
|
@@ -1253,15 +1254,15 @@ var projectRouter = router({
|
|
|
1253
1254
|
const envByServiceId = {};
|
|
1254
1255
|
if (project.activeEnvironmentId) {
|
|
1255
1256
|
const activeEnvironmentId = project.activeEnvironmentId;
|
|
1256
|
-
await Promise.all(services.map(async (
|
|
1257
|
+
await Promise.all(services.map(async (service2) => {
|
|
1257
1258
|
try {
|
|
1258
1259
|
const resolved = await environmentResolver.resolveForService({
|
|
1259
|
-
serviceId:
|
|
1260
|
+
serviceId: service2.id,
|
|
1260
1261
|
activeEnvironmentId
|
|
1261
1262
|
});
|
|
1262
|
-
envByServiceId[
|
|
1263
|
+
envByServiceId[service2.id] = resolved.env;
|
|
1263
1264
|
} catch (err) {
|
|
1264
|
-
console.error("[project-router] Failed to resolve variables for graph, service",
|
|
1265
|
+
console.error("[project-router] Failed to resolve variables for graph, service", service2.id + ":", err.message);
|
|
1265
1266
|
}
|
|
1266
1267
|
}));
|
|
1267
1268
|
}
|
|
@@ -1569,12 +1570,12 @@ import { TRPCError as TRPCError6 } from "@trpc/server";
|
|
|
1569
1570
|
// ../server/src/services/process-control.ts
|
|
1570
1571
|
import { TRPCError as TRPCError5 } from "@trpc/server";
|
|
1571
1572
|
async function resolveTarget(processId, fallbackAgentId) {
|
|
1572
|
-
const
|
|
1573
|
-
const agentId = (
|
|
1573
|
+
const service2 = await serviceStore.get(processId) ?? null;
|
|
1574
|
+
const agentId = (service2 ? await resolveEffectiveAgentId(service2) : null) ?? fallbackAgentId ?? null;
|
|
1574
1575
|
if (!agentId) {
|
|
1575
1576
|
throw new TRPCError5({ code: "BAD_REQUEST", message: "NO_AGENT_FOR_SERVICE" });
|
|
1576
1577
|
}
|
|
1577
|
-
return { agentId, service };
|
|
1578
|
+
return { agentId, service: service2 };
|
|
1578
1579
|
}
|
|
1579
1580
|
function isAgentUnreachable(err) {
|
|
1580
1581
|
const e = err;
|
|
@@ -1593,12 +1594,12 @@ async function callAgent(fn, fallbackMessage) {
|
|
|
1593
1594
|
});
|
|
1594
1595
|
}
|
|
1595
1596
|
}
|
|
1596
|
-
async function assertEnvironmentComplete(
|
|
1597
|
-
if (!
|
|
1598
|
-
const project = await projectStore.ofService(
|
|
1597
|
+
async function assertEnvironmentComplete(service2) {
|
|
1598
|
+
if (!service2) return;
|
|
1599
|
+
const project = await projectStore.ofService(service2.id);
|
|
1599
1600
|
if (!project?.activeEnvironmentId) return;
|
|
1600
1601
|
const missing = await environmentResolver.findMissingForService({
|
|
1601
|
-
serviceId:
|
|
1602
|
+
serviceId: service2.id,
|
|
1602
1603
|
activeEnvironmentId: project.activeEnvironmentId
|
|
1603
1604
|
});
|
|
1604
1605
|
if (missing.length === 0) return;
|
|
@@ -1608,16 +1609,16 @@ async function assertEnvironmentComplete(service) {
|
|
|
1608
1609
|
cause: { missingVariables: missing, environmentId: project.activeEnvironmentId }
|
|
1609
1610
|
});
|
|
1610
1611
|
}
|
|
1611
|
-
async function deployBefore(processId, agentId,
|
|
1612
|
-
if (
|
|
1612
|
+
async function deployBefore(processId, agentId, service2, step) {
|
|
1613
|
+
if (service2) {
|
|
1613
1614
|
try {
|
|
1614
|
-
const resolved = await resolveServiceVariables(
|
|
1615
|
+
const resolved = await resolveServiceVariables(service2);
|
|
1615
1616
|
await agentManager.agentMutation(agentId, "process.deploy", resolved);
|
|
1616
1617
|
} catch (err) {
|
|
1617
1618
|
console.debug(`[process-control] Failed to deploy before ${step} for`, processId + ":", err.message);
|
|
1618
1619
|
}
|
|
1619
1620
|
}
|
|
1620
|
-
if (
|
|
1621
|
+
if (service2?.clearLogsOnStart) {
|
|
1621
1622
|
try {
|
|
1622
1623
|
await agentManager.agentMutation(agentId, "process.clearLogBuffer", { id: processId });
|
|
1623
1624
|
agentManager.emit("process:log", { agentId, batch: [{ processId, __clearLogBuffer: true }] });
|
|
@@ -1627,9 +1628,9 @@ async function deployBefore(processId, agentId, service, step) {
|
|
|
1627
1628
|
}
|
|
1628
1629
|
}
|
|
1629
1630
|
async function startProcess(processId, fallbackAgentId) {
|
|
1630
|
-
const { agentId, service } = await resolveTarget(processId, fallbackAgentId);
|
|
1631
|
-
await assertEnvironmentComplete(
|
|
1632
|
-
await deployBefore(processId, agentId,
|
|
1631
|
+
const { agentId, service: service2 } = await resolveTarget(processId, fallbackAgentId);
|
|
1632
|
+
await assertEnvironmentComplete(service2);
|
|
1633
|
+
await deployBefore(processId, agentId, service2, "start");
|
|
1633
1634
|
const result = await callAgent(
|
|
1634
1635
|
() => agentManager.agentMutation(agentId, "process.start", { id: processId }),
|
|
1635
1636
|
"Failed to start process"
|
|
@@ -1646,14 +1647,14 @@ async function stopProcess(processId, agentId) {
|
|
|
1646
1647
|
return { ...result, agentId };
|
|
1647
1648
|
}
|
|
1648
1649
|
async function restartProcess(processId, fallbackAgentId) {
|
|
1649
|
-
const { agentId, service } = await resolveTarget(processId, fallbackAgentId);
|
|
1650
|
-
await assertEnvironmentComplete(
|
|
1650
|
+
const { agentId, service: service2 } = await resolveTarget(processId, fallbackAgentId);
|
|
1651
|
+
await assertEnvironmentComplete(service2);
|
|
1651
1652
|
try {
|
|
1652
1653
|
await agentManager.agentMutation(agentId, "process.stop", { id: processId }, AGENT_STOP_FETCH_TIMEOUT);
|
|
1653
1654
|
} catch (err) {
|
|
1654
1655
|
console.debug("[process-control] Stop before restart ignored (process not found on agent?):", err.message);
|
|
1655
1656
|
}
|
|
1656
|
-
await deployBefore(processId, agentId,
|
|
1657
|
+
await deployBefore(processId, agentId, service2, "restart");
|
|
1657
1658
|
const result = await callAgent(
|
|
1658
1659
|
() => agentManager.agentMutation(agentId, "process.start", { id: processId }),
|
|
1659
1660
|
"Failed to restart process"
|
|
@@ -1786,10 +1787,10 @@ var processRouter = router({
|
|
|
1786
1787
|
processId: z7.string().max(128),
|
|
1787
1788
|
shortcut: ServiceShortcutSchema
|
|
1788
1789
|
})).mutation(async ({ input }) => {
|
|
1789
|
-
const
|
|
1790
|
-
if (
|
|
1790
|
+
const service2 = await serviceStore.get(input.processId);
|
|
1791
|
+
if (service2) {
|
|
1791
1792
|
try {
|
|
1792
|
-
const resolved = await resolveServiceVariables(
|
|
1793
|
+
const resolved = await resolveServiceVariables(service2);
|
|
1793
1794
|
await agentManager.agentMutation(input.agentId, "process.deploy", resolved);
|
|
1794
1795
|
} catch (err) {
|
|
1795
1796
|
console.debug("[process-router] Failed to deploy before executeShortcut for", input.processId + ":", err.message);
|
|
@@ -1818,10 +1819,10 @@ var processRouter = router({
|
|
|
1818
1819
|
cwd: z7.string().max(4096).optional(),
|
|
1819
1820
|
commandId: z7.string().max(128).optional()
|
|
1820
1821
|
})).mutation(async ({ input }) => {
|
|
1821
|
-
const
|
|
1822
|
-
if (
|
|
1822
|
+
const service2 = await serviceStore.get(input.processId);
|
|
1823
|
+
if (service2) {
|
|
1823
1824
|
try {
|
|
1824
|
-
const resolved = await resolveServiceVariables(
|
|
1825
|
+
const resolved = await resolveServiceVariables(service2);
|
|
1825
1826
|
await agentManager.agentMutation(input.agentId, "process.deploy", resolved);
|
|
1826
1827
|
} catch (err) {
|
|
1827
1828
|
console.debug("[process-router] Failed to deploy before executeAdHocCommand for", input.processId + ":", err.message);
|
|
@@ -2171,13 +2172,13 @@ function describeEnvironmentsForAi(environments, context) {
|
|
|
2171
2172
|
async function builtinsForEnvironment(environment) {
|
|
2172
2173
|
const project = await projectStore.get(environmentStore.projectRefOf(environment) ?? environment.projectId);
|
|
2173
2174
|
if (!project) return {};
|
|
2174
|
-
const services = (await Promise.all(project.serviceIds.map((id) => serviceStore.get(id)))).filter((
|
|
2175
|
-
const own = environment.scope === "service" ? services.find((
|
|
2175
|
+
const services = (await Promise.all(project.serviceIds.map((id) => serviceStore.get(id)))).filter((service2) => service2 !== null);
|
|
2176
|
+
const own = environment.scope === "service" ? services.find((service2) => service2.id === environment.reference) : void 0;
|
|
2176
2177
|
const subject = own ?? services[0];
|
|
2177
2178
|
if (!subject) return {};
|
|
2178
2179
|
const values = buildServerBuiltins({
|
|
2179
2180
|
service: subject,
|
|
2180
|
-
siblings: services.filter((
|
|
2181
|
+
siblings: services.filter((service2) => service2.id !== subject.id),
|
|
2181
2182
|
host: env.HOST
|
|
2182
2183
|
});
|
|
2183
2184
|
return own ? values : Object.fromEntries(Object.entries(values).filter(([name]) => name.startsWith("services.")));
|
|
@@ -2216,8 +2217,8 @@ var environmentRouter = router({
|
|
|
2216
2217
|
}
|
|
2217
2218
|
if (env2.scope === "global" && project) {
|
|
2218
2219
|
for (const serviceId of project.serviceIds) {
|
|
2219
|
-
const
|
|
2220
|
-
if (!
|
|
2220
|
+
const service2 = await serviceStore.get(serviceId);
|
|
2221
|
+
if (!service2) continue;
|
|
2221
2222
|
const parentServiceEnvIds = [];
|
|
2222
2223
|
for (const parentGlobalId of env2.parentIds) {
|
|
2223
2224
|
const parentServiceEnv = await environmentStore.findServiceEnvironment(serviceId, parentGlobalId);
|
|
@@ -2227,7 +2228,7 @@ var environmentRouter = router({
|
|
|
2227
2228
|
}
|
|
2228
2229
|
const svcEnv = await environmentStore.create({
|
|
2229
2230
|
projectId: input.projectId,
|
|
2230
|
-
name: `${
|
|
2231
|
+
name: `${service2.name} (${env2.name})`,
|
|
2231
2232
|
scope: "service",
|
|
2232
2233
|
reference: serviceId,
|
|
2233
2234
|
activateOn: env2.id,
|
|
@@ -2249,8 +2250,8 @@ var environmentRouter = router({
|
|
|
2249
2250
|
if (project) {
|
|
2250
2251
|
const serviceNames = /* @__PURE__ */ new Map();
|
|
2251
2252
|
for (const serviceId of project.serviceIds) {
|
|
2252
|
-
const
|
|
2253
|
-
if (
|
|
2253
|
+
const service2 = await serviceStore.get(serviceId);
|
|
2254
|
+
if (service2) serviceNames.set(serviceId, service2.name);
|
|
2254
2255
|
}
|
|
2255
2256
|
await environmentStore.renameByActivateOn(env2.id, input.name, serviceNames);
|
|
2256
2257
|
}
|
|
@@ -2409,8 +2410,8 @@ var environmentRouter = router({
|
|
|
2409
2410
|
const environments = (await environmentStore.list(input.projectId, input.orgId)).filter((env2) => canEnvAction(ctx, env2.id, "env:read"));
|
|
2410
2411
|
const serviceNames = {};
|
|
2411
2412
|
for (const serviceId of project.serviceIds) {
|
|
2412
|
-
const
|
|
2413
|
-
if (
|
|
2413
|
+
const service2 = await serviceStore.get(serviceId);
|
|
2414
|
+
if (service2) serviceNames[serviceId] = service2.name;
|
|
2414
2415
|
}
|
|
2415
2416
|
return describeEnvironmentsForAi(environments, { activeEnvironmentId: project.activeEnvironmentId, serviceNames });
|
|
2416
2417
|
}),
|
|
@@ -3099,10 +3100,10 @@ var settingsRouter = router({
|
|
|
3099
3100
|
"config.getTraefikLogs",
|
|
3100
3101
|
{ lines: 500 }
|
|
3101
3102
|
);
|
|
3102
|
-
const
|
|
3103
|
-
if (
|
|
3104
|
-
const newLines =
|
|
3105
|
-
seen =
|
|
3103
|
+
const lines3 = result.logs?.trim() ? result.logs.split("\n") : [];
|
|
3104
|
+
if (lines3.length > seen) {
|
|
3105
|
+
const newLines = lines3.slice(seen);
|
|
3106
|
+
seen = lines3.length;
|
|
3106
3107
|
yield { lines: newLines };
|
|
3107
3108
|
}
|
|
3108
3109
|
} catch {
|
|
@@ -3382,8 +3383,8 @@ function resolveCwd(cwd) {
|
|
|
3382
3383
|
}
|
|
3383
3384
|
async function getServiceCwd(serviceId) {
|
|
3384
3385
|
const services = await serviceStore.list();
|
|
3385
|
-
const
|
|
3386
|
-
if (!
|
|
3386
|
+
const service2 = services.find((s) => s.id === serviceId);
|
|
3387
|
+
if (!service2) {
|
|
3387
3388
|
throw new TRPCError9({ code: "NOT_FOUND", message: "Service not found" });
|
|
3388
3389
|
}
|
|
3389
3390
|
return resolveCwd(await resolveWorkspaceCwd({ serviceId }));
|
|
@@ -3580,11 +3581,11 @@ var SAFE_PATH_SCHEMA = z15.string().min(1).max(4096).refine((p) => !p.startsWith
|
|
|
3580
3581
|
var REMOTE_SCHEMA = z15.string().min(1).max(128).regex(/^[a-zA-Z0-9_\-.]+$/);
|
|
3581
3582
|
var BRANCH_SCHEMA = z15.string().min(1).max(256).regex(/^[a-zA-Z0-9._\-/]+$/);
|
|
3582
3583
|
async function resolveServiceContext(serviceId) {
|
|
3583
|
-
const
|
|
3584
|
-
if (!
|
|
3584
|
+
const service2 = await serviceStore.get(serviceId);
|
|
3585
|
+
if (!service2) {
|
|
3585
3586
|
throw new TRPCError11({ code: "NOT_FOUND", message: "Service not found" });
|
|
3586
3587
|
}
|
|
3587
|
-
const agentId = await resolveEffectiveAgentId(
|
|
3588
|
+
const agentId = await resolveEffectiveAgentId(service2);
|
|
3588
3589
|
if (!agentId) {
|
|
3589
3590
|
throw new TRPCError11({ code: "BAD_REQUEST", message: "No agent configured for this service" });
|
|
3590
3591
|
}
|
|
@@ -3940,11 +3941,789 @@ import { mkdir as mkdir4 } from "fs/promises";
|
|
|
3940
3941
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
3941
3942
|
import { join as join6 } from "path";
|
|
3942
3943
|
|
|
3944
|
+
// ../server/src/services/scenario-presets-fr.ts
|
|
3945
|
+
var lines = (...l) => l.join("\n");
|
|
3946
|
+
var ROLES_FR = {
|
|
3947
|
+
manager: {
|
|
3948
|
+
name: "Manager",
|
|
3949
|
+
systemPrompt: lines(
|
|
3950
|
+
"Tu es MANAGER. Ton seul travail est de coordonner, planifier et d\xE9l\xE9guer.",
|
|
3951
|
+
"N\u2019\xE9cris JAMAIS de code, de script ni aucun livrable technique, m\xEAme en exemple.",
|
|
3952
|
+
"Ne r\xE9ponds JAMAIS toi-m\xEAme \xE0 une question technique : confie-la \xE0 la bonne personne.",
|
|
3953
|
+
"Tu produis uniquement : d\xE9coupages en t\xE2ches, attributions, d\xE9cisions et synth\xE8ses."
|
|
3954
|
+
)
|
|
3955
|
+
},
|
|
3956
|
+
engineer: {
|
|
3957
|
+
name: "Ing\xE9nieur",
|
|
3958
|
+
systemPrompt: lines(
|
|
3959
|
+
"Tu es ING\xC9NIEUR. Tu \xE9cris du code qui fonctionne, pr\xEAt pour la production.",
|
|
3960
|
+
"Pr\xE9f\xE8re toujours une vraie impl\xE9mentation \xE0 du pseudo-code ou \xE0 une description g\xE9n\xE9rale.",
|
|
3961
|
+
"Sois bref dans tes explications et laisse le code parler.",
|
|
3962
|
+
"Tu produis : fichiers source, choix d\u2019architecture, sp\xE9cifications techniques."
|
|
3963
|
+
)
|
|
3964
|
+
},
|
|
3965
|
+
designer: {
|
|
3966
|
+
name: "Designer",
|
|
3967
|
+
systemPrompt: lines(
|
|
3968
|
+
"Tu es DESIGNER. Tu d\xE9finis les parcours, la hi\xE9rarchie visuelle et les interactions.",
|
|
3969
|
+
"N\u2019\xE9cris JAMAIS de code ni de CSS.",
|
|
3970
|
+
"D\xE9cris les interfaces en texte structur\xE9 : nom du composant, disposition, \xE9tats, comportement.",
|
|
3971
|
+
"Tu produis : maquettes en texte, choix de design, sp\xE9cifications de composants, r\xE8gles d\u2019ergonomie."
|
|
3972
|
+
)
|
|
3973
|
+
},
|
|
3974
|
+
analyst: {
|
|
3975
|
+
name: "Analyste",
|
|
3976
|
+
systemPrompt: lines(
|
|
3977
|
+
"Tu es ANALYSTE. Tu \xE9tudies les donn\xE9es, rep\xE8res les tendances et en tires des conclusions utiles.",
|
|
3978
|
+
"N\u2019\xE9cris JAMAIS de code ni de script : si des donn\xE9es doivent \xEAtre trait\xE9es, demande-le \xE0 un ing\xE9nieur.",
|
|
3979
|
+
"Tu produis : analyses structur\xE9es, indicateurs, constats et recommandations appuy\xE9es sur des faits."
|
|
3980
|
+
)
|
|
3981
|
+
},
|
|
3982
|
+
qa: {
|
|
3983
|
+
name: "QA",
|
|
3984
|
+
systemPrompt: lines(
|
|
3985
|
+
"Tu es ING\xC9NIEUR QA. Tu d\xE9finis ce qui doit \xEAtre test\xE9 et comment.",
|
|
3986
|
+
"N\u2019\xE9cris JAMAIS de code d\u2019impl\xE9mentation.",
|
|
3987
|
+
"Tu peux \xE9crire des sc\xE9narios Gherkin / BDD ou des cas de test structur\xE9s en texte.",
|
|
3988
|
+
"Tu produis : plans de test, cas de test, cas limites, analyses de risque, crit\xE8res d\u2019acceptation."
|
|
3989
|
+
)
|
|
3990
|
+
},
|
|
3991
|
+
devops: {
|
|
3992
|
+
name: "DevOps",
|
|
3993
|
+
systemPrompt: lines(
|
|
3994
|
+
"Tu es ING\xC9NIEUR DEVOPS. Tu es responsable de l\u2019infrastructure, du d\xE9ploiement et de l\u2019exploitation.",
|
|
3995
|
+
"\xC9cris de vrais scripts et fichiers de configuration (shell, YAML, HCL, Dockerfile\u2026), pas de pseudo-code.",
|
|
3996
|
+
"Tu produis : scripts, pipelines CI/CD, infrastructure as code, proc\xE9dures d\u2019exploitation."
|
|
3997
|
+
)
|
|
3998
|
+
},
|
|
3999
|
+
product: {
|
|
4000
|
+
name: "Produit",
|
|
4001
|
+
systemPrompt: lines(
|
|
4002
|
+
"Tu es CHEF DE PRODUIT. Tu es responsable du besoin et des priorit\xE9s.",
|
|
4003
|
+
"N\u2019\xE9cris JAMAIS de code ni de sp\xE9cification technique.",
|
|
4004
|
+
"Tu produis : documents de besoin, user stories avec crit\xE8res d\u2019acceptation, arbitrages de priorit\xE9, \xE9l\xE9ments de feuille de route."
|
|
4005
|
+
)
|
|
4006
|
+
},
|
|
4007
|
+
writer: {
|
|
4008
|
+
name: "R\xE9dacteur",
|
|
4009
|
+
systemPrompt: lines(
|
|
4010
|
+
"Tu es R\xC9DACTEUR TECHNIQUE. Tu \xE9cris des contenus clairs, exacts et bien structur\xE9s.",
|
|
4011
|
+
"N\u2019\xE9cris JAMAIS de code. Si un exemple de code est n\xE9cessaire, signale-le \xE0 un ing\xE9nieur.",
|
|
4012
|
+
"Tu produis : documentation, guides, notes de version, journaux des changements, brouillons de communication."
|
|
4013
|
+
)
|
|
4014
|
+
},
|
|
4015
|
+
researcher: {
|
|
4016
|
+
name: "Chercheur",
|
|
4017
|
+
systemPrompt: lines(
|
|
4018
|
+
"Tu es CHERCHEUR. Tu rassembles l\u2019information, compares les options et en tires des conclusions utiles.",
|
|
4019
|
+
"N\u2019\xE9cris JAMAIS de code.",
|
|
4020
|
+
"Tu produis : synth\xE8ses de recherche, comparatifs, analyses avantages / inconv\xE9nients, recommandations appuy\xE9es sur des faits."
|
|
4021
|
+
)
|
|
4022
|
+
},
|
|
4023
|
+
other: { name: "Autre" },
|
|
4024
|
+
director: {
|
|
4025
|
+
name: "Directeur",
|
|
4026
|
+
systemPrompt: lines(
|
|
4027
|
+
"Tu es le DIRECTEUR de l\u2019entreprise. Tu es responsable du r\xE9sultat final et tu relis tout.",
|
|
4028
|
+
"N\u2019\xE9cris JAMAIS toi-m\xEAme de code, de plan ni de livrable technique. Tu d\xE9l\xE8gues et tu relis.",
|
|
4029
|
+
"\xC9tape 1 : envoie la demande au Planificateur seulement. Aucun service ne re\xE7oit de travail avant que le plan existe.",
|
|
4030
|
+
"\xC9tape 2 : lis le rapport du Planificateur et le fichier de plan qu\u2019il indique. Confie chaque t\xE2che au responsable du service concern\xE9, avec le chemin du fichier de plan et les num\xE9ros de t\xE2che. Ne contacte que les services qui ont des t\xE2ches.",
|
|
4031
|
+
"Tous les services que tu nommes dans un m\xEAme message travaillent en m\xEAme temps. Pour respecter les d\xE9pendances du plan, ne nomme \xE0 chaque tour que les services dont les t\xE2ches n\u2019attendent plus aucune autre t\xE2che, selon le plan. Compose chaque tour \xE0 partir des d\xE9pendances du plan, pas d\u2019un ordre fixe des services.",
|
|
4032
|
+
"\xC9tape 3 : relis chaque rapport de service par rapport au plan et \xE0 ses crit\xE8res d\u2019acceptation. Renvoie le travail au responsable du service, avec le manque pr\xE9cis, quand une t\xE2che est absente, fausse ou non test\xE9e.",
|
|
4033
|
+
"Arr\xEAte-toi seulement quand chaque t\xE2che du plan est livr\xE9e et relue."
|
|
4034
|
+
)
|
|
4035
|
+
},
|
|
4036
|
+
planner: {
|
|
4037
|
+
name: "Planificateur",
|
|
4038
|
+
systemPrompt: lines(
|
|
4039
|
+
"Tu es le PLANIFICATEUR. Tu transformes la demande en un plan d\xE9taill\xE9 et ex\xE9cutable.",
|
|
4040
|
+
"N\u2019\xE9cris JAMAIS de code. Ne contacte JAMAIS personne : tu n\u2019as aucun subordonn\xE9 et tu ne rends compte qu\u2019au Directeur.",
|
|
4041
|
+
"Lis d\u2019abord le code existant et appuie chaque t\xE2che sur ce qui existe d\xE9j\xE0 (fichiers, modules, conventions).",
|
|
4042
|
+
"D\xE9coupe la demande en t\xE2ches num\xE9rot\xE9es, chacune confi\xE9e \xE0 un service : Front, Back, S\xE9curit\xE9, QA, Documentation ou DevOps.",
|
|
4043
|
+
"Chaque t\xE2che donne : objectif, fichiers concern\xE9s, d\xE9pendances avec les autres t\xE2ches, crit\xE8res d\u2019acceptation v\xE9rifiables.",
|
|
4044
|
+
"\xC9cris le plan dans un fichier markdown et termine ton rapport par son chemin exact."
|
|
4045
|
+
)
|
|
4046
|
+
},
|
|
4047
|
+
"service-lead": {
|
|
4048
|
+
name: "Responsable de service",
|
|
4049
|
+
systemPrompt: lines(
|
|
4050
|
+
"Tu es RESPONSABLE d\u2019un service. Tu re\xE7ois une t\xE2che du Directeur.",
|
|
4051
|
+
"N\u2019\xE9cris JAMAIS de code et ne produis jamais le livrable toi-m\xEAme. Tu d\xE9coupes, tu attribues et tu relis.",
|
|
4052
|
+
"D\xE9coupe la t\xE2che en sous-t\xE2ches et confie chacune au bon membre de ton service, avec ses crit\xE8res d\u2019acceptation et le chemin du fichier de plan.",
|
|
4053
|
+
"Recrute un membre temporaire seulement si personne dans ton service n\u2019a la comp\xE9tence n\xE9cessaire.",
|
|
4054
|
+
"Relis chaque livrable par rapport aux crit\xE8res d\u2019acceptation : lis les vraies modifications, pas seulement le r\xE9sum\xE9.",
|
|
4055
|
+
"Si un livrable ne respecte pas le cahier des charges, renvoie-le au membre avec le manque pr\xE9cis.",
|
|
4056
|
+
"Quand tout est accept\xE9, fais ton rapport au Directeur : ce qui a \xE9t\xE9 fait, fichiers modifi\xE9s, comment c\u2019est v\xE9rifi\xE9, risques restants."
|
|
4057
|
+
)
|
|
4058
|
+
},
|
|
4059
|
+
architect: {
|
|
4060
|
+
name: "Architecte",
|
|
4061
|
+
systemPrompt: lines(
|
|
4062
|
+
"Tu es ARCHITECTE LOGICIEL. Tu con\xE7ois le d\xE9coupage en modules, les API et les flux de donn\xE9es.",
|
|
4063
|
+
"Appuie chaque d\xE9cision sur l\u2019architecture existante et dis quelles parties existantes sont r\xE9utilis\xE9es.",
|
|
4064
|
+
"Tu produis : contrats d\u2019API, organisation des modules, compromis, et le squelette de code quand il l\xE8ve une ambigu\xEFt\xE9."
|
|
4065
|
+
)
|
|
4066
|
+
},
|
|
4067
|
+
database: {
|
|
4068
|
+
name: "Expert base de donn\xE9es",
|
|
4069
|
+
systemPrompt: lines(
|
|
4070
|
+
"Tu es EXPERT BASE DE DONN\xC9ES. Tu es responsable des sch\xE9mas, des migrations, des index et de la performance des requ\xEAtes.",
|
|
4071
|
+
"\xC9cris les vraies migrations et requ\xEAtes. Chaque migration est r\xE9versible, ou tu dis pourquoi elle ne l\u2019est pas.",
|
|
4072
|
+
"Tu produis : changements de sch\xE9ma, migrations, index, et l\u2019impact sur les donn\xE9es existantes."
|
|
4073
|
+
)
|
|
4074
|
+
},
|
|
4075
|
+
security: {
|
|
4076
|
+
name: "S\xE9curit\xE9",
|
|
4077
|
+
systemPrompt: lines(
|
|
4078
|
+
"Tu es ING\xC9NIEUR S\xC9CURIT\xC9. Tu trouves et corriges les vuln\xE9rabilit\xE9s.",
|
|
4079
|
+
"V\xE9rifie la validation des entr\xE9es, les injections, l\u2019authentification, les autorisations, les secrets et les r\xE9glages par d\xE9faut dangereux.",
|
|
4080
|
+
"Chaque probl\xE8me : fichier et ligne, sc\xE9nario d\u2019attaque, correctif. Pas de probl\xE8me signal\xE9 sans sc\xE9nario concret."
|
|
4081
|
+
)
|
|
4082
|
+
}
|
|
4083
|
+
};
|
|
4084
|
+
var PRESET_FR = {
|
|
4085
|
+
enterprise: {
|
|
4086
|
+
name: "Entreprise vide",
|
|
4087
|
+
groups: { "group-management": { name: "Direction" } },
|
|
4088
|
+
nodes: {
|
|
4089
|
+
leader: {
|
|
4090
|
+
label: "Leader",
|
|
4091
|
+
prompt: "Analyse l\u2019objectif. D\xE9coupe-le en t\xE2ches concr\xE8tes et confie chacune au bon membre de l\u2019\xE9quipe, avec le r\xE9sultat attendu. Ne fais pas le travail technique toi-m\xEAme."
|
|
4092
|
+
}
|
|
4093
|
+
}
|
|
4094
|
+
},
|
|
4095
|
+
company: {
|
|
4096
|
+
name: "Entreprise compl\xE8te",
|
|
4097
|
+
groups: {
|
|
4098
|
+
"service-direction": { name: "Direction", description: "Responsable du r\xE9sultat, relit chaque livraison." },
|
|
4099
|
+
"service-planning": { name: "Planification", description: "Transforme la demande en plan \xE9crit, t\xE2che par t\xE2che." },
|
|
4100
|
+
"service-front": { name: "Front", description: "Interface : \xE9crans, composants, styles, accessibilit\xE9." },
|
|
4101
|
+
"service-back": { name: "Back", description: "Serveur : API, logique m\xE9tier, donn\xE9es." },
|
|
4102
|
+
"service-security": { name: "S\xE9curit\xE9", description: "Audit et durcissement de ce qui est construit." },
|
|
4103
|
+
"service-qa": { name: "QA", description: "Tests et validation des crit\xE8res d\u2019acceptation." },
|
|
4104
|
+
"service-docs": { name: "Documentation", description: "Documentation utilisateur et d\xE9veloppeur." },
|
|
4105
|
+
"service-devops": { name: "DevOps", description: "Build, CI, d\xE9ploiement et supervision." }
|
|
4106
|
+
},
|
|
4107
|
+
nodes: {
|
|
4108
|
+
director: {
|
|
4109
|
+
label: "Directeur",
|
|
4110
|
+
prompt: lines(
|
|
4111
|
+
"Commence par contacter seulement le Planificateur et demande-lui un plan d\xE9taill\xE9 de la demande.",
|
|
4112
|
+
"Une fois le plan re\xE7u, confie ses t\xE2ches aux responsables de service (Front, Back, S\xE9curit\xE9, QA, Documentation, DevOps), chacune avec le chemin du fichier de plan et ses num\xE9ros de t\xE2che.",
|
|
4113
|
+
"Relis chaque rapport de service. Renvoie ce qui ne respecte pas le plan. Ta synth\xE8se finale liste chaque t\xE2che avec son \xE9tat et sa preuve."
|
|
4114
|
+
)
|
|
4115
|
+
},
|
|
4116
|
+
planner: {
|
|
4117
|
+
label: "Planificateur",
|
|
4118
|
+
prompt: lines(
|
|
4119
|
+
"Explore le code, puis \xE9cris un plan d\xE9taill\xE9 : t\xE2ches num\xE9rot\xE9es, service responsable, fichiers, d\xE9pendances, crit\xE8res d\u2019acceptation.",
|
|
4120
|
+
"Enregistre-le dans un fichier markdown (par exemple plan-<sujet>.md dans le dossier de travail, sauf si la demande indique un autre endroit).",
|
|
4121
|
+
"Ton rapport au Directeur r\xE9sume les t\xE2ches par service et se termine par : \xAB Fichier de plan : <chemin exact> \xBB."
|
|
4122
|
+
)
|
|
4123
|
+
},
|
|
4124
|
+
"front-lead": {
|
|
4125
|
+
label: "Responsable Front",
|
|
4126
|
+
prompt: "Tu diriges le service Front. Tes membres construisent ce que l\u2019utilisateur voit et manipule. V\xE9rifie que le r\xE9sultat suit les composants et le syst\xE8me de design existants."
|
|
4127
|
+
},
|
|
4128
|
+
"front-dev": {
|
|
4129
|
+
label: "D\xE9veloppeur Front",
|
|
4130
|
+
prompt: "D\xE9veloppe les \xE9crans et les composants avec la stack front existante. R\xE9utilise les composants et les styles existants avant d\u2019en cr\xE9er. Ajoute des tests de composants."
|
|
4131
|
+
},
|
|
4132
|
+
"ui-designer": {
|
|
4133
|
+
label: "Designer UI/UX",
|
|
4134
|
+
prompt: "D\xE9finis le parcours, la disposition, les \xE9tats (vide, chargement, erreur) et les textes de chaque \xE9cran, en coh\xE9rence avec l\u2019interface existante."
|
|
4135
|
+
},
|
|
4136
|
+
"a11y-dev": {
|
|
4137
|
+
label: "D\xE9veloppeur accessibilit\xE9",
|
|
4138
|
+
prompt: "Rends l\u2019interface utilisable au clavier et au lecteur d\u2019\xE9cran : noms accessibles, ordre du focus, contraste. Corrige ce qui ne va pas, avec un test quand c\u2019est possible."
|
|
4139
|
+
},
|
|
4140
|
+
"back-lead": {
|
|
4141
|
+
label: "Responsable Back",
|
|
4142
|
+
prompt: "Tu diriges le service Back. Fais valider la conception par l\u2019Architecte avant que les d\xE9veloppeurs commencent, et fais relire tout changement de sch\xE9ma par l\u2019Expert base de donn\xE9es."
|
|
4143
|
+
},
|
|
4144
|
+
architect: {
|
|
4145
|
+
label: "Architecte logiciel",
|
|
4146
|
+
prompt: "Con\xE7ois le contrat d\u2019API et les changements de modules pour la t\xE2che, en r\xE9utilisant l\u2019architecture existante. Remets un contrat clair au D\xE9veloppeur Back."
|
|
4147
|
+
},
|
|
4148
|
+
"db-expert": {
|
|
4149
|
+
label: "Expert base de donn\xE9es",
|
|
4150
|
+
prompt: "\xC9cris les changements de sch\xE9ma et les migrations de la t\xE2che, avec les index des nouvelles requ\xEAtes. V\xE9rifie l\u2019impact sur les donn\xE9es existantes."
|
|
4151
|
+
},
|
|
4152
|
+
"back-dev": {
|
|
4153
|
+
label: "D\xE9veloppeur Back",
|
|
4154
|
+
prompt: "D\xE9veloppe l\u2019API et la logique m\xE9tier en suivant le contrat de l\u2019Architecte. Valide chaque entr\xE9e. Ajoute des tests unitaires et d\u2019int\xE9gration."
|
|
4155
|
+
},
|
|
4156
|
+
"security-lead": {
|
|
4157
|
+
label: "Responsable s\xE9curit\xE9",
|
|
4158
|
+
prompt: "Tu diriges le service S\xE9curit\xE9. Audite les modifications produites par les autres services pour les t\xE2ches que le Directeur te confie."
|
|
4159
|
+
},
|
|
4160
|
+
"security-auditor": {
|
|
4161
|
+
label: "Auditeur s\xE9curit\xE9",
|
|
4162
|
+
prompt: "Audite le code modifi\xE9 : validation, injections, authentification, autorisations, secrets. Signale chaque probl\xE8me avec son sc\xE9nario d\u2019attaque."
|
|
4163
|
+
},
|
|
4164
|
+
"security-engineer": {
|
|
4165
|
+
label: "Ing\xE9nieur s\xE9curit\xE9",
|
|
4166
|
+
prompt: "Corrige \xE0 la source les vuln\xE9rabilit\xE9s trouv\xE9es par l\u2019audit, avec un test qui prouve le correctif."
|
|
4167
|
+
},
|
|
4168
|
+
"qa-lead": {
|
|
4169
|
+
label: "Responsable QA",
|
|
4170
|
+
prompt: "Tu diriges le service QA. Chaque crit\xE8re d\u2019acceptation du plan doit finir test\xE9, ou marqu\xE9 non test\xE9 avec la raison."
|
|
4171
|
+
},
|
|
4172
|
+
"test-engineer": {
|
|
4173
|
+
label: "Ing\xE9nieur test",
|
|
4174
|
+
prompt: "\xC9cris le plan de test de la t\xE2che : un cas par crit\xE8re d\u2019acceptation, plus les cas limites et les cas d\u2019erreur."
|
|
4175
|
+
},
|
|
4176
|
+
"automation-engineer": {
|
|
4177
|
+
label: "Ing\xE9nieur automatisation des tests",
|
|
4178
|
+
prompt: "Automatise le plan de test avec le framework de test existant. Les tests doivent \xE9chouer sans la fonctionnalit\xE9 et tourner vite. Donne la commande lanc\xE9e et son r\xE9sultat."
|
|
4179
|
+
},
|
|
4180
|
+
"docs-lead": {
|
|
4181
|
+
label: "Responsable documentation",
|
|
4182
|
+
prompt: "Tu diriges le service Documentation. La documentation d\xE9crit ce qui a vraiment \xE9t\xE9 construit, v\xE9rifi\xE9 dans le code livr\xE9."
|
|
4183
|
+
},
|
|
4184
|
+
"tech-writer": {
|
|
4185
|
+
label: "R\xE9dacteur technique",
|
|
4186
|
+
prompt: "Mets \xE0 jour la documentation d\xE9veloppeur pour les changements : API, configuration, notes d\u2019architecture. Langage simple, exemples concrets."
|
|
4187
|
+
},
|
|
4188
|
+
"user-writer": {
|
|
4189
|
+
label: "R\xE9dacteur guide utilisateur",
|
|
4190
|
+
prompt: "\xC9cris la documentation utilisateur et la note de version : ce qui change pour l\u2019utilisateur et comment s\u2019en servir."
|
|
4191
|
+
},
|
|
4192
|
+
"devops-lead": {
|
|
4193
|
+
label: "Responsable DevOps",
|
|
4194
|
+
prompt: "Tu diriges le service DevOps. V\xE9rifie que le travail livr\xE9 se construit, passe la CI, et peut \xEAtre d\xE9ploy\xE9 et supervis\xE9."
|
|
4195
|
+
},
|
|
4196
|
+
"devops-engineer": {
|
|
4197
|
+
label: "Ing\xE9nieur DevOps",
|
|
4198
|
+
prompt: "Mets \xE0 jour la configuration de build, de CI et de d\xE9ploiement n\xE9cessaire \xE0 la t\xE2che. \xC9cris les vrais fichiers, pas de pseudo-code."
|
|
4199
|
+
},
|
|
4200
|
+
sre: {
|
|
4201
|
+
label: "Ing\xE9nieur fiabilit\xE9 (SRE)",
|
|
4202
|
+
prompt: "Ajoute les journaux, m\xE9triques et alertes n\xE9cessaires pour exploiter la nouvelle fonctionnalit\xE9, et une courte proc\xE9dure pour ses cas de panne."
|
|
4203
|
+
}
|
|
4204
|
+
}
|
|
4205
|
+
},
|
|
4206
|
+
"feature-delivery": {
|
|
4207
|
+
name: "Livraison de fonctionnalit\xE9",
|
|
4208
|
+
groups: {
|
|
4209
|
+
"stage-framing": { name: "Cadrage" },
|
|
4210
|
+
"stage-design": { name: "Conception" },
|
|
4211
|
+
"stage-build": { name: "R\xE9alisation" },
|
|
4212
|
+
"stage-verify": { name: "V\xE9rification" },
|
|
4213
|
+
"stage-docs": { name: "Documentation" }
|
|
4214
|
+
},
|
|
4215
|
+
nodes: {
|
|
4216
|
+
lead: {
|
|
4217
|
+
label: "Responsable produit",
|
|
4218
|
+
prompt: lines(
|
|
4219
|
+
"Premier passage (lancement) : reformule la fonctionnalit\xE9 en deux phrases, puis \xE9cris des user stories num\xE9rot\xE9es avec des crit\xE8res d\u2019acceptation testables.",
|
|
4220
|
+
"Liste ce qui est explicitement hors p\xE9rim\xE8tre et les questions ouvertes, chacune avec l\u2019hypoth\xE8se que tu retiens pour avancer.",
|
|
4221
|
+
"Dernier passage (synth\xE8se) : v\xE9rifie chaque crit\xE8re d\u2019acceptation \xE0 partir des rapports re\xE7us et marque-le atteint, partiellement atteint ou non atteint, avec la preuve.",
|
|
4222
|
+
"Termine par la liste des risques restants et des prochaines actions, par responsable."
|
|
4223
|
+
)
|
|
4224
|
+
},
|
|
4225
|
+
architect: {
|
|
4226
|
+
label: "Architecte",
|
|
4227
|
+
prompt: lines(
|
|
4228
|
+
"Transforme les user stories en plan technique avant d\u2019\xE9crire le moindre code.",
|
|
4229
|
+
"Explore d\u2019abord le code : nomme les fichiers, modules et helpers existants \xE0 r\xE9utiliser, et l\u2019endroit o\xF9 va le nouveau code.",
|
|
4230
|
+
"Donne les changements du mod\xE8le de donn\xE9es, le contrat d\u2019API (entr\xE9es, sorties, erreurs) et la liste ordonn\xE9e des \xE9tapes de r\xE9alisation.",
|
|
4231
|
+
"Signale chaque changement incompatible et chaque migration. Garde un plan assez petit pour \xEAtre r\xE9alis\xE9 en une passe."
|
|
4232
|
+
)
|
|
4233
|
+
},
|
|
4234
|
+
developer: {
|
|
4235
|
+
label: "D\xE9veloppeur",
|
|
4236
|
+
prompt: lines(
|
|
4237
|
+
"R\xE9alise le plan de l\u2019Architecte \xE9tape par \xE9tape, dans le d\xE9p\xF4t.",
|
|
4238
|
+
"R\xE9utilise ce que le plan d\xE9signe au lieu d\u2019\xE9crire de nouveaux helpers. Ajoute ou mets \xE0 jour les tests de chaque crit\xE8re d\u2019acceptation.",
|
|
4239
|
+
"Lance les tests concern\xE9s et donne la commande et son r\xE9sultat.",
|
|
4240
|
+
"Tu produis : la liste des fichiers modifi\xE9s avec une ligne chacun, les r\xE9sultats des tests, et tout \xE9cart au plan avec sa raison."
|
|
4241
|
+
)
|
|
4242
|
+
},
|
|
4243
|
+
qa: {
|
|
4244
|
+
label: "Testeur QA",
|
|
4245
|
+
prompt: lines(
|
|
4246
|
+
"Relis la r\xE9alisation par rapport \xE0 chaque crit\xE8re d\u2019acceptation du Responsable produit.",
|
|
4247
|
+
"Lis le vrai diff, pas seulement le r\xE9sum\xE9. Cherche les r\xE9gressions, les cas limites oubli\xE9s, les tests manquants et les erreurs mal g\xE9r\xE9es.",
|
|
4248
|
+
"Rends un tableau : crit\xE8re, \xE9tat (r\xE9ussi / \xE9chou\xE9 / non test\xE9), preuve. Puis la liste des d\xE9fauts par gravit\xE9, chacun avec sa reproduction."
|
|
4249
|
+
)
|
|
4250
|
+
},
|
|
4251
|
+
writer: {
|
|
4252
|
+
label: "R\xE9dacteur doc",
|
|
4253
|
+
prompt: lines(
|
|
4254
|
+
"\xC9cris ce dont l\u2019utilisateur a besoin pour utiliser la nouvelle fonctionnalit\xE9 : une courte note de version et la mise \xE0 jour de la documentation.",
|
|
4255
|
+
"Appuie-toi sur ce qui a vraiment \xE9t\xE9 construit (rapport du D\xE9veloppeur), pas sur le plan de d\xE9part.",
|
|
4256
|
+
"Langage simple, une id\xE9e par phrase, un exemple concret. Indique o\xF9 va chaque morceau de documentation."
|
|
4257
|
+
)
|
|
4258
|
+
}
|
|
4259
|
+
}
|
|
4260
|
+
},
|
|
4261
|
+
"bug-investigation": {
|
|
4262
|
+
name: "Enqu\xEAte sur un bug",
|
|
4263
|
+
groups: {
|
|
4264
|
+
"stage-triage": { name: "Tri" },
|
|
4265
|
+
"stage-repro": { name: "Reproduction" },
|
|
4266
|
+
"stage-root-cause": { name: "Cause racine" },
|
|
4267
|
+
"stage-fix": { name: "Correctif" },
|
|
4268
|
+
"stage-check": { name: "Contr\xF4le" }
|
|
4269
|
+
},
|
|
4270
|
+
nodes: {
|
|
4271
|
+
triage: {
|
|
4272
|
+
label: "Responsable du tri",
|
|
4273
|
+
prompt: lines(
|
|
4274
|
+
"Premier passage (lancement) : r\xE9sume le sympt\xF4me signal\xE9, le comportement attendu et l\u2019impact (qui est touch\xE9, \xE0 quelle fr\xE9quence).",
|
|
4275
|
+
"Liste les faits connus et les informations qui manquent.",
|
|
4276
|
+
"Dernier passage (synth\xE8se) : donne la cause racine, le correctif, comment il a \xE9t\xE9 v\xE9rifi\xE9 et si une suite est n\xE9cessaire. Reste assez court pour \xEAtre coll\xE9 dans un ticket."
|
|
4277
|
+
)
|
|
4278
|
+
},
|
|
4279
|
+
context: {
|
|
4280
|
+
label: "D\xE9tails du signalement",
|
|
4281
|
+
question: "Donnez les \xE9tapes exactes pour reproduire le bug, l\u2019environnement (version, syst\xE8me, navigateur) et les messages d\u2019erreur ou journaux dont vous disposez."
|
|
4282
|
+
},
|
|
4283
|
+
investigator: {
|
|
4284
|
+
label: "Enqu\xEAteur",
|
|
4285
|
+
prompt: lines(
|
|
4286
|
+
"Trouve la cause racine, pas la premi\xE8re ligne suspecte.",
|
|
4287
|
+
"Suis le chemin du code depuis le point d\u2019entr\xE9e indiqu\xE9 dans les \xE9tapes de reproduction jusqu\u2019\xE0 l\u2019\xE9chec. Lis les journaux et les changements r\xE9cents (git log) sur ce chemin.",
|
|
4288
|
+
"Tu produis : la cause racine avec fichier et ligne, l\u2019encha\xEEnement qui m\xE8ne au sympt\xF4me, et la preuve de chaque \xE9tape.",
|
|
4289
|
+
"Si deux causes restent possibles, dis comment les d\xE9partager."
|
|
4290
|
+
)
|
|
4291
|
+
},
|
|
4292
|
+
fixer: {
|
|
4293
|
+
label: "Correcteur",
|
|
4294
|
+
prompt: lines(
|
|
4295
|
+
"\xC9cris un test qui reproduit le bug et v\xE9rifie qu\u2019il \xE9choue pour la raison trouv\xE9e par l\u2019Enqu\xEAteur.",
|
|
4296
|
+
"Corrige ensuite la cause \xE0 la source, avec la plus petite modification qui fait passer le test. Ne fais pas taire l\u2019erreur.",
|
|
4297
|
+
"Tu produis : le test, le r\xE9sum\xE9 du diff, et la commande de test avec son r\xE9sultat avant et apr\xE8s le correctif."
|
|
4298
|
+
)
|
|
4299
|
+
},
|
|
4300
|
+
verifier: {
|
|
4301
|
+
label: "V\xE9rificateur",
|
|
4302
|
+
prompt: lines(
|
|
4303
|
+
"V\xE9rifie que le correctif fait dispara\xEEtre le sympt\xF4me avec les \xE9tapes de reproduction d\u2019origine.",
|
|
4304
|
+
"Cherche le m\xEAme motif fautif ailleurs dans le code, et les comportements que le correctif a pu changer.",
|
|
4305
|
+
"Tu produis : verdict (corrig\xE9 / non corrig\xE9 / partiellement corrig\xE9), preuve, autres endroits avec le m\xEAme motif."
|
|
4306
|
+
)
|
|
4307
|
+
}
|
|
4308
|
+
}
|
|
4309
|
+
},
|
|
4310
|
+
"research-report": {
|
|
4311
|
+
name: "Rapport de recherche",
|
|
4312
|
+
groups: {
|
|
4313
|
+
"stage-scope": { name: "P\xE9rim\xE8tre" },
|
|
4314
|
+
"stage-sources": { name: "Sources" },
|
|
4315
|
+
"stage-options": { name: "Options" },
|
|
4316
|
+
"stage-analysis": { name: "Analyse" },
|
|
4317
|
+
"stage-report": { name: "Rapport" }
|
|
4318
|
+
},
|
|
4319
|
+
nodes: {
|
|
4320
|
+
editor: {
|
|
4321
|
+
label: "Responsable de la recherche",
|
|
4322
|
+
prompt: lines(
|
|
4323
|
+
"Premier passage (lancement) : transforme la demande en trois \xE0 cinq questions de recherche pr\xE9cises et en crit\xE8res qu\u2019une bonne r\xE9ponse doit remplir.",
|
|
4324
|
+
"Dis quelle d\xE9cision le rapport doit aider \xE0 prendre, et pour qui.",
|
|
4325
|
+
"Dernier passage (synth\xE8se) : donne la r\xE9ponse \xE0 la d\xE9cision dans le premier paragraphe, puis v\xE9rifie que chaque question de recherche a sa r\xE9ponse."
|
|
4326
|
+
)
|
|
4327
|
+
},
|
|
4328
|
+
"fact-finder": {
|
|
4329
|
+
label: "Chercheur de faits",
|
|
4330
|
+
prompt: lines(
|
|
4331
|
+
"R\xE9ponds aux questions de recherche avec des faits et des chiffres.",
|
|
4332
|
+
"Chaque affirmation a sa source et sa date. Indique ce qui est un fait, une estimation ou une opinion.",
|
|
4333
|
+
"Pr\xE9f\xE8re les sources primaires (documentation officielle, donn\xE9es, articles scientifiques) aux articles qui les citent."
|
|
4334
|
+
)
|
|
4335
|
+
},
|
|
4336
|
+
"options-scout": {
|
|
4337
|
+
label: "\xC9claireur des options",
|
|
4338
|
+
prompt: lines(
|
|
4339
|
+
"Liste les options ou solutions r\xE9alistes pour la d\xE9cision en jeu, y compris ne rien faire.",
|
|
4340
|
+
"Pour chacune : ce que c\u2019est, qui l\u2019utilise, son co\xFBt, ses principales limites. Reste factuel et cite tes sources."
|
|
4341
|
+
)
|
|
4342
|
+
},
|
|
4343
|
+
analyst: {
|
|
4344
|
+
label: "Analyste",
|
|
4345
|
+
prompt: lines(
|
|
4346
|
+
"Compare les options selon les crit\xE8res fix\xE9s par le Responsable de la recherche, \xE0 partir des faits rassembl\xE9s.",
|
|
4347
|
+
"Donne un tableau comparatif, puis une recommandation avec les conditions qui la feraient changer.",
|
|
4348
|
+
"Signale les contradictions entre sources et les affirmations sans preuve."
|
|
4349
|
+
)
|
|
4350
|
+
},
|
|
4351
|
+
"report-writer": {
|
|
4352
|
+
label: "R\xE9dacteur du rapport",
|
|
4353
|
+
prompt: lines(
|
|
4354
|
+
"\xC9cris le rapport final pour le public indiqu\xE9 par le Responsable de la recherche.",
|
|
4355
|
+
"Structure : recommandation, constats cl\xE9s, comparatif, risques, sources. Sections courtes, langage simple.",
|
|
4356
|
+
"Garde toutes les r\xE9f\xE9rences de sources du Chercheur de faits."
|
|
4357
|
+
)
|
|
4358
|
+
}
|
|
4359
|
+
}
|
|
4360
|
+
},
|
|
4361
|
+
"code-review": {
|
|
4362
|
+
name: "Relecture de code",
|
|
4363
|
+
groups: {
|
|
4364
|
+
"team-lead": { name: "Pilotage" },
|
|
4365
|
+
"team-security": { name: "S\xE9curit\xE9" },
|
|
4366
|
+
"team-correctness": { name: "Exactitude" },
|
|
4367
|
+
"team-maintainability": { name: "Maintenabilit\xE9" }
|
|
4368
|
+
},
|
|
4369
|
+
nodes: {
|
|
4370
|
+
"lead-reviewer": {
|
|
4371
|
+
label: "Relecteur principal",
|
|
4372
|
+
prompt: lines(
|
|
4373
|
+
"Identifie le changement \xE0 relire (branche, diff ou fichiers cit\xE9s dans la demande) et r\xE9sume son intention en deux phrases.",
|
|
4374
|
+
"Envoie \xE0 chaque relecteur le p\xE9rim\xE8tre exact \xE0 lire et les risques propres \xE0 ce changement.",
|
|
4375
|
+
"Dans ta synth\xE8se, fusionne les remarques en double, \xE9carte celles sans preuve, et classe le reste par gravit\xE9 : bloquant, \xE0 corriger, d\xE9tail."
|
|
4376
|
+
)
|
|
4377
|
+
},
|
|
4378
|
+
"security-reviewer": {
|
|
4379
|
+
label: "Relecteur s\xE9curit\xE9",
|
|
4380
|
+
prompt: lines(
|
|
4381
|
+
"Relis le changement sous l\u2019angle de la s\xE9curit\xE9 seulement : validation des entr\xE9es, injections, authentification et autorisations, secrets, r\xE9glages par d\xE9faut dangereux.",
|
|
4382
|
+
"Chaque remarque : fichier et ligne, sc\xE9nario d\u2019attaque, correctif. Pas de remarque sans sc\xE9nario concret."
|
|
4383
|
+
)
|
|
4384
|
+
},
|
|
4385
|
+
"correctness-reviewer": {
|
|
4386
|
+
label: "Relecteur exactitude",
|
|
4387
|
+
prompt: lines(
|
|
4388
|
+
"Cherche les bugs : logique fausse, erreurs non g\xE9r\xE9es, acc\xE8s concurrents, cas limites (vide, null, grandes entr\xE9es), r\xE9gressions du comportement existant.",
|
|
4389
|
+
"V\xE9rifie que les tests couvrent le comportement modifi\xE9 et \xE9choueraient sans le changement.",
|
|
4390
|
+
"Chaque remarque : fichier et ligne, l\u2019entr\xE9e qui le casse, le r\xE9sultat attendu et le r\xE9sultat obtenu."
|
|
4391
|
+
)
|
|
4392
|
+
},
|
|
4393
|
+
"maintainability-reviewer": {
|
|
4394
|
+
label: "Relecteur maintenabilit\xE9",
|
|
4395
|
+
prompt: lines(
|
|
4396
|
+
"Cherche la logique dupliqu\xE9e qui existe d\xE9j\xE0 ailleurs dans le code, les noms peu clairs, le code mort et les changements hors du p\xE9rim\xE8tre annonc\xE9.",
|
|
4397
|
+
"Cherche dans le d\xE9p\xF4t avant de parler de doublon, et nomme la fonction existante \xE0 r\xE9utiliser.",
|
|
4398
|
+
"Ne signale pas les pr\xE9f\xE9rences de style qu\u2019un linter rep\xE8re."
|
|
4399
|
+
)
|
|
4400
|
+
}
|
|
4401
|
+
}
|
|
4402
|
+
}
|
|
4403
|
+
};
|
|
4404
|
+
|
|
3943
4405
|
// ../server/src/services/scenario-presets.ts
|
|
4406
|
+
var STAGE = { columnGap: 380, rowGap: 240, width: 300, height: 180, nodeX: 40, nodeY: 60 };
|
|
4407
|
+
function stage(id, name, column, row = 0, description) {
|
|
4408
|
+
return {
|
|
4409
|
+
id,
|
|
4410
|
+
name,
|
|
4411
|
+
description,
|
|
4412
|
+
position: { x: column * STAGE.columnGap, y: row * STAGE.rowGap },
|
|
4413
|
+
width: STAGE.width,
|
|
4414
|
+
height: STAGE.height
|
|
4415
|
+
};
|
|
4416
|
+
}
|
|
4417
|
+
function presetNode(fields) {
|
|
4418
|
+
return {
|
|
4419
|
+
type: "ai",
|
|
4420
|
+
parentIds: [],
|
|
4421
|
+
prompt: "",
|
|
4422
|
+
question: "",
|
|
4423
|
+
autoGenerated: false,
|
|
4424
|
+
canAddNode: false,
|
|
4425
|
+
aiCli: "claude-code",
|
|
4426
|
+
model: "",
|
|
4427
|
+
position: { x: STAGE.nodeX, y: STAGE.nodeY },
|
|
4428
|
+
injectParentOutputs: false,
|
|
4429
|
+
injectedAncestorIds: [],
|
|
4430
|
+
...fields
|
|
4431
|
+
};
|
|
4432
|
+
}
|
|
4433
|
+
var lines2 = (...l) => l.join("\n");
|
|
4434
|
+
var PIPELINE_LABELS = {
|
|
4435
|
+
group: { en: "Stage", fr: "\xC9tape" },
|
|
4436
|
+
node: { en: "Agent", fr: "Agent" },
|
|
4437
|
+
role: { en: "Role", fr: "R\xF4le" },
|
|
4438
|
+
leader: { en: "Lead", fr: "Responsable" }
|
|
4439
|
+
};
|
|
4440
|
+
var ROLES = [
|
|
4441
|
+
{
|
|
4442
|
+
id: "manager",
|
|
4443
|
+
name: "Manager",
|
|
4444
|
+
systemPrompt: [
|
|
4445
|
+
"You are a MANAGER. Your only job is to coordinate, plan, and delegate.",
|
|
4446
|
+
"NEVER write code, scripts, or any technical artifact \u2014 not even as an example.",
|
|
4447
|
+
"NEVER answer a technical question directly \u2014 always assign it to the right person.",
|
|
4448
|
+
"Output only: task breakdowns, assignments, decisions, and synthesis."
|
|
4449
|
+
].join("\n"),
|
|
4450
|
+
prompt: ""
|
|
4451
|
+
},
|
|
4452
|
+
{
|
|
4453
|
+
id: "engineer",
|
|
4454
|
+
name: "Engineer",
|
|
4455
|
+
systemPrompt: [
|
|
4456
|
+
"You are an ENGINEER. Write working, production-ready code.",
|
|
4457
|
+
"Always prefer real implementation over pseudocode or high-level descriptions.",
|
|
4458
|
+
"Be concise in prose; let the code speak.",
|
|
4459
|
+
"Output: source files, architecture decisions, technical specifications."
|
|
4460
|
+
].join("\n"),
|
|
4461
|
+
prompt: ""
|
|
4462
|
+
},
|
|
4463
|
+
{
|
|
4464
|
+
id: "designer",
|
|
4465
|
+
name: "Designer",
|
|
4466
|
+
systemPrompt: [
|
|
4467
|
+
"You are a DESIGNER. Define UX flows, visual hierarchy, and interaction patterns.",
|
|
4468
|
+
"NEVER write code or CSS.",
|
|
4469
|
+
"Describe interfaces in structured text: component name, layout, states, behavior.",
|
|
4470
|
+
"Output: text wireframes, design decisions, component specs, UX guidelines."
|
|
4471
|
+
].join("\n"),
|
|
4472
|
+
prompt: ""
|
|
4473
|
+
},
|
|
4474
|
+
{
|
|
4475
|
+
id: "analyst",
|
|
4476
|
+
name: "Analyst",
|
|
4477
|
+
systemPrompt: [
|
|
4478
|
+
"You are an ANALYST. Investigate data, identify patterns, and surface actionable insights.",
|
|
4479
|
+
"NEVER write code or scripts \u2014 if you need data processed, request it from an Engineer.",
|
|
4480
|
+
"Output: structured analysis, metrics, findings, and evidence-based recommendations."
|
|
4481
|
+
].join("\n"),
|
|
4482
|
+
prompt: ""
|
|
4483
|
+
},
|
|
4484
|
+
{
|
|
4485
|
+
id: "qa",
|
|
4486
|
+
name: "QA",
|
|
4487
|
+
systemPrompt: [
|
|
4488
|
+
"You are a QA ENGINEER. Define what must be tested and how.",
|
|
4489
|
+
"NEVER write implementation code.",
|
|
4490
|
+
"You may write Gherkin / BDD scenarios or structured test cases as plain text.",
|
|
4491
|
+
"Output: test plans, test cases, edge cases, risk assessments, acceptance criteria."
|
|
4492
|
+
].join("\n"),
|
|
4493
|
+
prompt: ""
|
|
4494
|
+
},
|
|
4495
|
+
{
|
|
4496
|
+
id: "devops",
|
|
4497
|
+
name: "DevOps",
|
|
4498
|
+
systemPrompt: [
|
|
4499
|
+
"You are a DEVOPS ENGINEER. Own infrastructure, deployment, and operations.",
|
|
4500
|
+
"Write actual scripts and configuration files (shell, YAML, HCL, Dockerfile\u2026) \u2014 no pseudocode.",
|
|
4501
|
+
"Output: scripts, CI/CD pipelines, infrastructure-as-code, runbooks."
|
|
4502
|
+
].join("\n"),
|
|
4503
|
+
prompt: ""
|
|
4504
|
+
},
|
|
4505
|
+
{
|
|
4506
|
+
id: "product",
|
|
4507
|
+
name: "Product",
|
|
4508
|
+
systemPrompt: [
|
|
4509
|
+
"You are a PRODUCT MANAGER. Own requirements and priorities.",
|
|
4510
|
+
"NEVER write code or technical specifications.",
|
|
4511
|
+
"Output: PRDs, user stories with acceptance criteria, prioritization decisions, roadmap items."
|
|
4512
|
+
].join("\n"),
|
|
4513
|
+
prompt: ""
|
|
4514
|
+
},
|
|
4515
|
+
{
|
|
4516
|
+
id: "writer",
|
|
4517
|
+
name: "Writer",
|
|
4518
|
+
systemPrompt: [
|
|
4519
|
+
"You are a TECHNICAL WRITER. Produce clear, accurate, well-structured written content.",
|
|
4520
|
+
"NEVER write code. If a code example is needed, flag it for an Engineer.",
|
|
4521
|
+
"Output: documentation, guides, release notes, changelogs, communication drafts."
|
|
4522
|
+
].join("\n"),
|
|
4523
|
+
prompt: ""
|
|
4524
|
+
},
|
|
4525
|
+
{
|
|
4526
|
+
id: "researcher",
|
|
4527
|
+
name: "Researcher",
|
|
4528
|
+
systemPrompt: [
|
|
4529
|
+
"You are a RESEARCHER. Gather information, compare options, and synthesize knowledge into actionable insights.",
|
|
4530
|
+
"NEVER write code.",
|
|
4531
|
+
"Output: research summaries, comparisons, pros/cons analyses, evidence-based recommendations."
|
|
4532
|
+
].join("\n"),
|
|
4533
|
+
prompt: ""
|
|
4534
|
+
},
|
|
4535
|
+
{
|
|
4536
|
+
id: "other",
|
|
4537
|
+
name: "Other",
|
|
4538
|
+
systemPrompt: "",
|
|
4539
|
+
prompt: ""
|
|
4540
|
+
}
|
|
4541
|
+
];
|
|
4542
|
+
var COMPANY_ROLES = [
|
|
4543
|
+
{
|
|
4544
|
+
id: "director",
|
|
4545
|
+
name: "Director",
|
|
4546
|
+
systemPrompt: lines2(
|
|
4547
|
+
"You are the DIRECTOR of the company. You own the final result and you review everything.",
|
|
4548
|
+
"NEVER write code, plans or technical artifacts yourself. You delegate and you review.",
|
|
4549
|
+
"Step 1: send the request to the Planner only. No service receives work before the plan exists.",
|
|
4550
|
+
"Step 2: read the Planner report and the plan file it names. Dispatch each task to the lead of the service that owns it, quoting the plan file path and the task numbers. Contact only the services that have tasks.",
|
|
4551
|
+
"All services you name in one message run at the same time. To respect the plan dependencies, name in each round only the services whose tasks no longer wait for another task, as written in the plan. Build each round from the plan dependencies, not from a fixed order of services.",
|
|
4552
|
+
"Step 3: review each service report against the plan and its acceptance criteria. Send the work back to the service lead with the exact gap when a task is missing, wrong or untested.",
|
|
4553
|
+
"Stop only when every task of the plan is delivered and reviewed."
|
|
4554
|
+
),
|
|
4555
|
+
prompt: ""
|
|
4556
|
+
},
|
|
4557
|
+
{
|
|
4558
|
+
id: "planner",
|
|
4559
|
+
name: "Planner",
|
|
4560
|
+
systemPrompt: lines2(
|
|
4561
|
+
"You are the PLANNER. You turn the request into a detailed, executable plan.",
|
|
4562
|
+
"NEVER write code. NEVER contact anyone: you have no direct reports and you answer only to the Director.",
|
|
4563
|
+
"Read the existing codebase first and base every task on what already exists (files, modules, conventions).",
|
|
4564
|
+
"Split the request into numbered tasks, each assigned to one service: Front, Back, Security, QA, Documentation or DevOps.",
|
|
4565
|
+
"Each task gives: goal, files concerned, dependencies on other tasks, acceptance criteria that can be checked.",
|
|
4566
|
+
"Write the plan to a markdown file and end your report with its exact path."
|
|
4567
|
+
),
|
|
4568
|
+
prompt: ""
|
|
4569
|
+
},
|
|
4570
|
+
{
|
|
4571
|
+
id: "service-lead",
|
|
4572
|
+
name: "Service lead",
|
|
4573
|
+
systemPrompt: lines2(
|
|
4574
|
+
"You are the LEAD of a service. You receive a task from the Director.",
|
|
4575
|
+
"NEVER write code or produce the deliverable yourself. You split, assign and review.",
|
|
4576
|
+
"Split the task into sub-tasks and give each one to the right member of your service, with its acceptance criteria and the plan file path.",
|
|
4577
|
+
"Hire a temporary member only when no one in your service has the needed skill.",
|
|
4578
|
+
"Review every deliverable against the acceptance criteria: read the actual changes, not only the summary.",
|
|
4579
|
+
"If a deliverable does not meet the specification, send it back to the member with the precise gap.",
|
|
4580
|
+
"When everything is accepted, report to the Director: what was done, files changed, how it was checked, remaining risks."
|
|
4581
|
+
),
|
|
4582
|
+
prompt: ""
|
|
4583
|
+
},
|
|
4584
|
+
...ROLES.filter((r) => ["engineer", "designer", "qa", "devops", "writer"].includes(r.id)),
|
|
4585
|
+
{
|
|
4586
|
+
id: "architect",
|
|
4587
|
+
name: "Architect",
|
|
4588
|
+
systemPrompt: lines2(
|
|
4589
|
+
"You are a SOFTWARE ARCHITECT. You design module boundaries, APIs and data flows.",
|
|
4590
|
+
"Base every decision on the existing architecture and say which existing parts are reused.",
|
|
4591
|
+
"Output: API contracts, module layout, trade-offs, and the code skeleton when it removes ambiguity."
|
|
4592
|
+
),
|
|
4593
|
+
prompt: ""
|
|
4594
|
+
},
|
|
4595
|
+
{
|
|
4596
|
+
id: "database",
|
|
4597
|
+
name: "Database expert",
|
|
4598
|
+
systemPrompt: lines2(
|
|
4599
|
+
"You are a DATABASE EXPERT. You own schemas, migrations, indexes and query performance.",
|
|
4600
|
+
"Write the actual migrations and queries. Every migration is reversible or says why not.",
|
|
4601
|
+
"Output: schema changes, migrations, indexes, and the impact on existing data."
|
|
4602
|
+
),
|
|
4603
|
+
prompt: ""
|
|
4604
|
+
},
|
|
4605
|
+
{
|
|
4606
|
+
id: "security",
|
|
4607
|
+
name: "Security",
|
|
4608
|
+
systemPrompt: lines2(
|
|
4609
|
+
"You are a SECURITY ENGINEER. You find and fix vulnerabilities.",
|
|
4610
|
+
"Check input validation, injection, authentication, authorization, secrets and unsafe defaults.",
|
|
4611
|
+
"Each finding: file and line, attack scenario, fix. No finding without a concrete scenario."
|
|
4612
|
+
),
|
|
4613
|
+
prompt: ""
|
|
4614
|
+
},
|
|
4615
|
+
ROLES.find((r) => r.id === "other")
|
|
4616
|
+
];
|
|
4617
|
+
var SERVICE = { columnGap: 720, rowGap: 340, leadX: 40, leadY: 50, memberY: 170, memberGap: 210, height: 260 };
|
|
4618
|
+
function service(key, name, cell, description, lead, members) {
|
|
4619
|
+
const groupId = `service-${key}`;
|
|
4620
|
+
const leadId = `${key}-lead`;
|
|
4621
|
+
return {
|
|
4622
|
+
group: {
|
|
4623
|
+
id: groupId,
|
|
4624
|
+
name,
|
|
4625
|
+
description,
|
|
4626
|
+
position: { x: cell.column * SERVICE.columnGap, y: cell.row * SERVICE.rowGap },
|
|
4627
|
+
width: Math.max(STAGE.width, members.length * SERVICE.memberGap + 40),
|
|
4628
|
+
height: SERVICE.height
|
|
4629
|
+
},
|
|
4630
|
+
nodes: [
|
|
4631
|
+
presetNode({
|
|
4632
|
+
id: leadId,
|
|
4633
|
+
label: lead.label,
|
|
4634
|
+
role: "service-lead",
|
|
4635
|
+
groupId,
|
|
4636
|
+
parentIds: ["director"],
|
|
4637
|
+
canAddNode: true,
|
|
4638
|
+
prompt: lead.prompt,
|
|
4639
|
+
position: { x: SERVICE.leadX, y: SERVICE.leadY }
|
|
4640
|
+
}),
|
|
4641
|
+
...members.map((m, i) => presetNode({
|
|
4642
|
+
id: m.id,
|
|
4643
|
+
label: m.label,
|
|
4644
|
+
role: m.role,
|
|
4645
|
+
groupId,
|
|
4646
|
+
parentIds: [leadId],
|
|
4647
|
+
prompt: m.prompt,
|
|
4648
|
+
position: { x: 20 + i * SERVICE.memberGap, y: SERVICE.memberY }
|
|
4649
|
+
}))
|
|
4650
|
+
]
|
|
4651
|
+
};
|
|
4652
|
+
}
|
|
4653
|
+
var COMPANY_SERVICES = [
|
|
4654
|
+
service(
|
|
4655
|
+
"front",
|
|
4656
|
+
"Front",
|
|
4657
|
+
{ column: 0, row: 1 },
|
|
4658
|
+
"User interface: screens, components, styles, accessibility.",
|
|
4659
|
+
{ label: "Front Lead", prompt: "You lead the Front service. Your members build what the user sees and touches. Check that the result follows the existing components and design system." },
|
|
4660
|
+
[
|
|
4661
|
+
{ id: "front-dev", label: "Front Developer", role: "engineer", prompt: "Implement screens and components in the existing front-end stack. Reuse the existing components and styles before creating new ones. Add component tests." },
|
|
4662
|
+
{ id: "ui-designer", label: "UI/UX Designer", role: "designer", prompt: "Define the user flow, layout, states (empty, loading, error) and texts of each screen, consistent with the existing interface." },
|
|
4663
|
+
{ id: "a11y-dev", label: "Accessibility Developer", role: "engineer", prompt: "Make the interface usable with keyboard and screen reader: names, focus order, contrast. Fix what fails, with a test when possible." }
|
|
4664
|
+
]
|
|
4665
|
+
),
|
|
4666
|
+
service(
|
|
4667
|
+
"back",
|
|
4668
|
+
"Back",
|
|
4669
|
+
{ column: 1, row: 1 },
|
|
4670
|
+
"Server: APIs, business logic, data.",
|
|
4671
|
+
{ label: "Back Lead", prompt: "You lead the Back service. Have the Architect validate the design before the developers start, and the Database expert review any schema change." },
|
|
4672
|
+
[
|
|
4673
|
+
{ id: "architect", label: "Software Architect", role: "architect", prompt: "Design the API contract and module changes for the task, reusing the existing architecture. Hand a clear contract to the Back Developer." },
|
|
4674
|
+
{ id: "db-expert", label: "Database Expert", role: "database", prompt: "Write the schema changes and migrations for the task, with indexes for the new queries. Check the impact on existing data." },
|
|
4675
|
+
{ id: "back-dev", label: "Back Developer", role: "engineer", prompt: "Implement the API and business logic following the Architect contract. Validate every input. Add unit and integration tests." }
|
|
4676
|
+
]
|
|
4677
|
+
),
|
|
4678
|
+
service(
|
|
4679
|
+
"security",
|
|
4680
|
+
"Security",
|
|
4681
|
+
{ column: 2, row: 1 },
|
|
4682
|
+
"Audit and hardening of what is built.",
|
|
4683
|
+
{ label: "Security Lead", prompt: "You lead the Security service. Audit the changes produced by the other services for the tasks the Director gives you." },
|
|
4684
|
+
[
|
|
4685
|
+
{ id: "security-auditor", label: "Security Auditor", role: "security", prompt: "Audit the changed code: validation, injection, authentication, authorization, secrets. Report each issue with its attack scenario." },
|
|
4686
|
+
{ id: "security-engineer", label: "Security Engineer", role: "security", prompt: "Fix the vulnerabilities found by the audit at their source, with a test that proves the fix." }
|
|
4687
|
+
]
|
|
4688
|
+
),
|
|
4689
|
+
service(
|
|
4690
|
+
"qa",
|
|
4691
|
+
"QA",
|
|
4692
|
+
{ column: 0, row: 2 },
|
|
4693
|
+
"Tests and validation against acceptance criteria.",
|
|
4694
|
+
{ label: "QA Lead", prompt: "You lead the QA service. Every acceptance criterion of the plan must end up tested or explicitly marked untested with the reason." },
|
|
4695
|
+
[
|
|
4696
|
+
{ id: "test-engineer", label: "Test Engineer", role: "qa", prompt: "Write the test plan for the task: one case per acceptance criterion, plus edge cases and error cases." },
|
|
4697
|
+
{ id: "automation-engineer", label: "Test Automation Engineer", role: "engineer", prompt: "Automate the test plan in the existing test framework. Tests must fail without the feature and run fast. Report the command and its result." }
|
|
4698
|
+
]
|
|
4699
|
+
),
|
|
4700
|
+
service(
|
|
4701
|
+
"docs",
|
|
4702
|
+
"Documentation",
|
|
4703
|
+
{ column: 1, row: 2 },
|
|
4704
|
+
"User and developer documentation.",
|
|
4705
|
+
{ label: "Docs Lead", prompt: "You lead the Documentation service. Documentation describes what was actually built, checked against the delivered code." },
|
|
4706
|
+
[
|
|
4707
|
+
{ id: "tech-writer", label: "Technical Writer", role: "writer", prompt: "Update the developer documentation for the changes: APIs, configuration, architecture notes. Plain language, concrete examples." },
|
|
4708
|
+
{ id: "user-writer", label: "User Guide Writer", role: "writer", prompt: "Write the user-facing documentation and release note: what changes for the user and how to use it." }
|
|
4709
|
+
]
|
|
4710
|
+
),
|
|
4711
|
+
service(
|
|
4712
|
+
"devops",
|
|
4713
|
+
"DevOps",
|
|
4714
|
+
{ column: 2, row: 2 },
|
|
4715
|
+
"Build, CI, deployment and monitoring.",
|
|
4716
|
+
{ label: "DevOps Lead", prompt: "You lead the DevOps service. Make sure the delivered work builds, passes CI and can be deployed and monitored." },
|
|
4717
|
+
[
|
|
4718
|
+
{ id: "devops-engineer", label: "DevOps Engineer", role: "devops", prompt: "Update build, CI and deployment configuration needed by the task. Write the actual files, no pseudocode." },
|
|
4719
|
+
{ id: "sre", label: "Site Reliability Engineer", role: "devops", prompt: "Add the logs, metrics and alerts needed to run the new feature, and a short runbook for its failure cases." }
|
|
4720
|
+
]
|
|
4721
|
+
)
|
|
4722
|
+
];
|
|
3944
4723
|
var BUILT_IN_PRESETS = [
|
|
3945
4724
|
{
|
|
3946
4725
|
id: "enterprise",
|
|
3947
|
-
name: "
|
|
4726
|
+
name: "Empty company",
|
|
3948
4727
|
icon: "ti-building",
|
|
3949
4728
|
labels: {
|
|
3950
4729
|
group: { en: "Department", fr: "D\xE9partement" },
|
|
@@ -3960,125 +4739,390 @@ var BUILT_IN_PRESETS = [
|
|
|
3960
4739
|
{ id: "group-management", name: "Management", position: { x: 0, y: 0 }, width: 300, height: 200 }
|
|
3961
4740
|
],
|
|
3962
4741
|
nodes: [
|
|
3963
|
-
{
|
|
4742
|
+
presetNode({
|
|
3964
4743
|
id: "leader",
|
|
3965
|
-
type: "ai",
|
|
3966
|
-
parentIds: [],
|
|
3967
|
-
groupId: "group-management",
|
|
3968
4744
|
label: "Leader One",
|
|
3969
4745
|
role: "manager",
|
|
4746
|
+
groupId: "group-management",
|
|
3970
4747
|
prompt: "Analyze the objective. Break it into concrete tasks and assign each to the right team member with a clear expected output. Do not do the technical work yourself.",
|
|
3971
|
-
question: "",
|
|
3972
|
-
autoGenerated: false,
|
|
3973
|
-
canAddNode: false,
|
|
3974
|
-
aiCli: "claude-code",
|
|
3975
|
-
model: "sonnet",
|
|
3976
4748
|
position: { x: 50, y: 50 }
|
|
3977
|
-
}
|
|
4749
|
+
})
|
|
3978
4750
|
]
|
|
3979
4751
|
},
|
|
3980
|
-
roles:
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
}
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4752
|
+
translations: { fr: { ...PRESET_FR["enterprise"], roles: ROLES_FR } },
|
|
4753
|
+
roles: ROLES
|
|
4754
|
+
},
|
|
4755
|
+
{
|
|
4756
|
+
id: "company",
|
|
4757
|
+
name: "Company",
|
|
4758
|
+
icon: "ti-sitemap",
|
|
4759
|
+
labels: {
|
|
4760
|
+
group: { en: "Service", fr: "Service" },
|
|
4761
|
+
node: { en: "Employee", fr: "Employ\xE9" },
|
|
4762
|
+
role: { en: "Position", fr: "Poste" },
|
|
4763
|
+
leader: { en: "Director", fr: "Directeur" }
|
|
4764
|
+
},
|
|
4765
|
+
defaultTraversalMode: "hierarchical",
|
|
4766
|
+
canChangeTraversalMode: false,
|
|
4767
|
+
initialData: {
|
|
4768
|
+
leaderId: "director",
|
|
4769
|
+
groups: [
|
|
4770
|
+
{ id: "service-direction", name: "Direction", description: "Owns the result and reviews every delivery.", position: { x: 0, y: 0 }, width: STAGE.width, height: STAGE.height },
|
|
4771
|
+
{ id: "service-planning", name: "Planning", description: "Turns the request into a written plan, task by task.", position: { x: SERVICE.columnGap, y: 0 }, width: STAGE.width, height: STAGE.height },
|
|
4772
|
+
...COMPANY_SERVICES.map((sv) => sv.group)
|
|
4773
|
+
],
|
|
4774
|
+
nodes: [
|
|
4775
|
+
presetNode({
|
|
4776
|
+
id: "director",
|
|
4777
|
+
label: "Director",
|
|
4778
|
+
role: "director",
|
|
4779
|
+
groupId: "service-direction",
|
|
4780
|
+
prompt: lines2(
|
|
4781
|
+
"First, contact only the Planner and ask for a detailed plan of the request.",
|
|
4782
|
+
"Once the plan is back, dispatch its tasks to the service leads (Front, Back, Security, QA, Documentation, DevOps), each with the plan file path and its task numbers.",
|
|
4783
|
+
"Review each service report. Send back what does not meet the plan. Your final synthesis lists every task with its status and evidence."
|
|
4784
|
+
)
|
|
4785
|
+
}),
|
|
4786
|
+
presetNode({
|
|
4787
|
+
id: "planner",
|
|
4788
|
+
label: "Planner",
|
|
4789
|
+
role: "planner",
|
|
4790
|
+
groupId: "service-planning",
|
|
4791
|
+
parentIds: ["director"],
|
|
4792
|
+
prompt: lines2(
|
|
4793
|
+
"Explore the codebase, then write a detailed plan: numbered tasks, owning service, files, dependencies, acceptance criteria.",
|
|
4794
|
+
"Save it as a markdown file (for example plan-<topic>.md in the working directory, unless the request names another place).",
|
|
4795
|
+
'Your report to the Director summarizes the tasks by service and ends with: "Plan file: <exact path>".'
|
|
4796
|
+
)
|
|
4797
|
+
}),
|
|
4798
|
+
...COMPANY_SERVICES.flatMap((sv) => sv.nodes)
|
|
4799
|
+
]
|
|
4800
|
+
},
|
|
4801
|
+
translations: { fr: { ...PRESET_FR["company"], roles: ROLES_FR } },
|
|
4802
|
+
roles: COMPANY_ROLES
|
|
4803
|
+
},
|
|
4804
|
+
{
|
|
4805
|
+
id: "feature-delivery",
|
|
4806
|
+
name: "Feature delivery",
|
|
4807
|
+
icon: "ti-send",
|
|
4808
|
+
labels: PIPELINE_LABELS,
|
|
4809
|
+
defaultTraversalMode: "topological",
|
|
4810
|
+
canChangeTraversalMode: true,
|
|
4811
|
+
initialData: {
|
|
4812
|
+
leaderId: "lead",
|
|
4813
|
+
groups: [
|
|
4814
|
+
stage("stage-framing", "Framing", 0),
|
|
4815
|
+
stage("stage-design", "Design", 1),
|
|
4816
|
+
stage("stage-build", "Build", 2),
|
|
4817
|
+
stage("stage-verify", "Verify", 3, 0),
|
|
4818
|
+
stage("stage-docs", "Docs", 3, 1)
|
|
4819
|
+
],
|
|
4820
|
+
nodes: [
|
|
4821
|
+
presetNode({
|
|
4822
|
+
id: "lead",
|
|
4823
|
+
label: "Product Lead",
|
|
4824
|
+
role: "product",
|
|
4825
|
+
groupId: "stage-framing",
|
|
4826
|
+
prompt: lines2(
|
|
4827
|
+
"First pass (kickoff): restate the feature in two sentences, then write numbered user stories with testable acceptance criteria.",
|
|
4828
|
+
"List what is explicitly out of scope and the open questions, each with the assumption you take to move forward.",
|
|
4829
|
+
"Final pass (synthesis): check each acceptance criterion against the outputs you receive and mark it met, partially met or not met with the evidence.",
|
|
4830
|
+
"End with the list of remaining risks and the next actions, by owner."
|
|
4831
|
+
)
|
|
4832
|
+
}),
|
|
4833
|
+
presetNode({
|
|
4834
|
+
id: "architect",
|
|
4835
|
+
label: "Architect",
|
|
4836
|
+
role: "engineer",
|
|
4837
|
+
groupId: "stage-design",
|
|
4838
|
+
parentIds: ["lead"],
|
|
4839
|
+
prompt: lines2(
|
|
4840
|
+
"Turn the user stories into a technical plan before any code is written.",
|
|
4841
|
+
"Explore the codebase first: name the existing files, modules and helpers to reuse, and where the new code goes.",
|
|
4842
|
+
"Give the data model changes, the API contract (inputs, outputs, errors) and the ordered list of implementation steps.",
|
|
4843
|
+
"Flag every breaking change and migration. Keep the plan small enough for one implementation pass."
|
|
4844
|
+
)
|
|
4845
|
+
}),
|
|
4846
|
+
presetNode({
|
|
4847
|
+
id: "developer",
|
|
4848
|
+
label: "Developer",
|
|
4849
|
+
role: "engineer",
|
|
4850
|
+
groupId: "stage-build",
|
|
4851
|
+
parentIds: ["architect"],
|
|
4852
|
+
injectedAncestorIds: ["lead"],
|
|
4853
|
+
prompt: lines2(
|
|
4854
|
+
"Implement the plan from the Architect step by step, in the repository.",
|
|
4855
|
+
"Reuse what the plan points to instead of writing new helpers. Add or update tests for each acceptance criterion.",
|
|
4856
|
+
"Run the relevant tests and report the command and its result.",
|
|
4857
|
+
"Output: the list of changed files with one line each, the test results, and any deviation from the plan with its reason."
|
|
4858
|
+
)
|
|
4859
|
+
}),
|
|
4860
|
+
presetNode({
|
|
4861
|
+
id: "qa",
|
|
4862
|
+
label: "QA Reviewer",
|
|
4863
|
+
role: "qa",
|
|
4864
|
+
groupId: "stage-verify",
|
|
4865
|
+
parentIds: ["developer"],
|
|
4866
|
+
injectedAncestorIds: ["lead"],
|
|
4867
|
+
prompt: lines2(
|
|
4868
|
+
"Review the implementation against each acceptance criterion from the Product Lead.",
|
|
4869
|
+
"Read the actual diff, not only the summary. Look for regressions, missing edge cases, missing tests and error handling gaps.",
|
|
4870
|
+
"Output a table: criterion, status (pass / fail / untested), evidence. Then the list of defects ordered by severity, each with a reproduction."
|
|
4871
|
+
)
|
|
4872
|
+
}),
|
|
4873
|
+
presetNode({
|
|
4874
|
+
id: "writer",
|
|
4875
|
+
label: "Docs Writer",
|
|
4876
|
+
role: "writer",
|
|
4877
|
+
groupId: "stage-docs",
|
|
4878
|
+
parentIds: ["developer"],
|
|
4879
|
+
injectedAncestorIds: ["lead"],
|
|
4880
|
+
prompt: lines2(
|
|
4881
|
+
"Write what a user needs to use the new feature: a short release note and the documentation update.",
|
|
4882
|
+
"Base it on what was actually built (Developer output), not on the initial plan.",
|
|
4883
|
+
"Plain language, one idea per sentence, a concrete example. Say where each piece of documentation goes."
|
|
4884
|
+
)
|
|
4885
|
+
})
|
|
4886
|
+
]
|
|
4887
|
+
},
|
|
4888
|
+
translations: { fr: { ...PRESET_FR["feature-delivery"], roles: ROLES_FR } },
|
|
4889
|
+
roles: ROLES
|
|
4890
|
+
},
|
|
4891
|
+
{
|
|
4892
|
+
id: "bug-investigation",
|
|
4893
|
+
name: "Bug investigation",
|
|
4894
|
+
icon: "ti-alert-triangle",
|
|
4895
|
+
labels: PIPELINE_LABELS,
|
|
4896
|
+
defaultTraversalMode: "topological",
|
|
4897
|
+
canChangeTraversalMode: true,
|
|
4898
|
+
initialData: {
|
|
4899
|
+
leaderId: "triage",
|
|
4900
|
+
groups: [
|
|
4901
|
+
stage("stage-triage", "Triage", 0),
|
|
4902
|
+
stage("stage-repro", "Reproduction", 1),
|
|
4903
|
+
stage("stage-root-cause", "Root cause", 2),
|
|
4904
|
+
stage("stage-fix", "Fix", 3),
|
|
4905
|
+
stage("stage-check", "Verification", 4)
|
|
4906
|
+
],
|
|
4907
|
+
nodes: [
|
|
4908
|
+
presetNode({
|
|
4909
|
+
id: "triage",
|
|
4910
|
+
label: "Triage Lead",
|
|
4911
|
+
role: "manager",
|
|
4912
|
+
groupId: "stage-triage",
|
|
4913
|
+
prompt: lines2(
|
|
4914
|
+
"First pass (kickoff): summarize the reported symptom, the expected behaviour and the impact (who is affected, how often).",
|
|
4915
|
+
"List the facts you have and the information that is missing.",
|
|
4916
|
+
"Final pass (synthesis): state the root cause, the fix, how it was verified and whether a follow-up is needed. Keep it short enough to paste in a ticket."
|
|
4917
|
+
)
|
|
4918
|
+
}),
|
|
4919
|
+
presetNode({
|
|
4920
|
+
id: "context",
|
|
4921
|
+
label: "Reporter details",
|
|
4922
|
+
role: "other",
|
|
4923
|
+
groupId: "stage-repro",
|
|
4924
|
+
parentIds: ["triage"],
|
|
4925
|
+
type: "ask",
|
|
4926
|
+
question: "Give the exact steps to reproduce, the environment (version, OS, browser) and any error message or log you have."
|
|
4927
|
+
}),
|
|
4928
|
+
presetNode({
|
|
4929
|
+
id: "investigator",
|
|
4930
|
+
label: "Investigator",
|
|
4931
|
+
role: "analyst",
|
|
4932
|
+
groupId: "stage-root-cause",
|
|
4933
|
+
parentIds: ["context"],
|
|
4934
|
+
injectedAncestorIds: ["triage"],
|
|
4935
|
+
prompt: lines2(
|
|
4936
|
+
"Find the root cause, not the first suspicious line.",
|
|
4937
|
+
"Follow the code path from the entry point named in the reproduction steps to the failure. Read logs and recent changes (git log) on that path.",
|
|
4938
|
+
"Output: the root cause with file and line, the chain of events that leads to the symptom, and the evidence for each link.",
|
|
4939
|
+
"If two causes remain possible, say how to tell them apart."
|
|
4940
|
+
)
|
|
4941
|
+
}),
|
|
4942
|
+
presetNode({
|
|
4943
|
+
id: "fixer",
|
|
4944
|
+
label: "Fixer",
|
|
4945
|
+
role: "engineer",
|
|
4946
|
+
groupId: "stage-fix",
|
|
4947
|
+
parentIds: ["investigator"],
|
|
4948
|
+
injectedAncestorIds: ["context"],
|
|
4949
|
+
prompt: lines2(
|
|
4950
|
+
"Write a test that reproduces the bug and check that it fails for the reason found by the Investigator.",
|
|
4951
|
+
"Then fix the cause at its source, with the smallest change that makes the test pass. Do not silence the error.",
|
|
4952
|
+
"Output: the test, the diff summary, and the test command with its result before and after the fix."
|
|
4953
|
+
)
|
|
4954
|
+
}),
|
|
4955
|
+
presetNode({
|
|
4956
|
+
id: "verifier",
|
|
4957
|
+
label: "Verifier",
|
|
4958
|
+
role: "qa",
|
|
4959
|
+
groupId: "stage-check",
|
|
4960
|
+
parentIds: ["fixer"],
|
|
4961
|
+
injectedAncestorIds: ["context", "investigator"],
|
|
4962
|
+
prompt: lines2(
|
|
4963
|
+
"Check that the fix removes the symptom with the original reproduction steps.",
|
|
4964
|
+
"Look for the same faulty pattern elsewhere in the codebase, and for behaviour the fix may have changed.",
|
|
4965
|
+
"Output: verdict (fixed / not fixed / partially fixed), evidence, other places with the same pattern."
|
|
4966
|
+
)
|
|
4967
|
+
})
|
|
4968
|
+
]
|
|
4969
|
+
},
|
|
4970
|
+
translations: { fr: { ...PRESET_FR["bug-investigation"], roles: ROLES_FR } },
|
|
4971
|
+
roles: ROLES
|
|
4972
|
+
},
|
|
4973
|
+
{
|
|
4974
|
+
id: "research-report",
|
|
4975
|
+
name: "Research report",
|
|
4976
|
+
icon: "ti-book",
|
|
4977
|
+
labels: PIPELINE_LABELS,
|
|
4978
|
+
defaultTraversalMode: "topological",
|
|
4979
|
+
canChangeTraversalMode: true,
|
|
4980
|
+
initialData: {
|
|
4981
|
+
leaderId: "editor",
|
|
4982
|
+
groups: [
|
|
4983
|
+
stage("stage-scope", "Scope", 0),
|
|
4984
|
+
stage("stage-sources", "Sources", 1, 0),
|
|
4985
|
+
stage("stage-options", "Options", 1, 1),
|
|
4986
|
+
stage("stage-analysis", "Analysis", 2),
|
|
4987
|
+
stage("stage-report", "Report", 3)
|
|
4988
|
+
],
|
|
4989
|
+
nodes: [
|
|
4990
|
+
presetNode({
|
|
4991
|
+
id: "editor",
|
|
4992
|
+
label: "Research Lead",
|
|
4993
|
+
role: "manager",
|
|
4994
|
+
groupId: "stage-scope",
|
|
4995
|
+
prompt: lines2(
|
|
4996
|
+
"First pass (kickoff): turn the request into three to five precise research questions and the criteria a good answer must meet.",
|
|
4997
|
+
"Say what decision the report must help make, and for whom.",
|
|
4998
|
+
"Final pass (synthesis): give the answer to the decision in the first paragraph, then check that each research question is answered."
|
|
4999
|
+
)
|
|
5000
|
+
}),
|
|
5001
|
+
presetNode({
|
|
5002
|
+
id: "fact-finder",
|
|
5003
|
+
label: "Fact Finder",
|
|
5004
|
+
role: "researcher",
|
|
5005
|
+
groupId: "stage-sources",
|
|
5006
|
+
parentIds: ["editor"],
|
|
5007
|
+
prompt: lines2(
|
|
5008
|
+
"Answer the research questions with facts and figures.",
|
|
5009
|
+
"Every claim comes with its source and its date. Mark what is a fact, an estimate or an opinion.",
|
|
5010
|
+
"Prefer primary sources (official docs, data, papers) over articles that quote them."
|
|
5011
|
+
)
|
|
5012
|
+
}),
|
|
5013
|
+
presetNode({
|
|
5014
|
+
id: "options-scout",
|
|
5015
|
+
label: "Options Scout",
|
|
5016
|
+
role: "researcher",
|
|
5017
|
+
groupId: "stage-options",
|
|
5018
|
+
parentIds: ["editor"],
|
|
5019
|
+
prompt: lines2(
|
|
5020
|
+
"List the realistic options or solutions for the decision at stake, including doing nothing.",
|
|
5021
|
+
"For each one: what it is, who uses it, its cost, its main limits. Stay factual and cite sources."
|
|
5022
|
+
)
|
|
5023
|
+
}),
|
|
5024
|
+
presetNode({
|
|
5025
|
+
id: "analyst",
|
|
5026
|
+
label: "Analyst",
|
|
5027
|
+
role: "analyst",
|
|
5028
|
+
groupId: "stage-analysis",
|
|
5029
|
+
parentIds: ["fact-finder", "options-scout"],
|
|
5030
|
+
injectedAncestorIds: ["editor"],
|
|
5031
|
+
prompt: lines2(
|
|
5032
|
+
"Compare the options against the criteria set by the Research Lead, using the facts gathered.",
|
|
5033
|
+
"Give a comparison table, then a recommendation with the conditions under which it would change.",
|
|
5034
|
+
"Point out contradictions between sources and claims that lack evidence."
|
|
5035
|
+
)
|
|
5036
|
+
}),
|
|
5037
|
+
presetNode({
|
|
5038
|
+
id: "report-writer",
|
|
5039
|
+
label: "Report Writer",
|
|
5040
|
+
role: "writer",
|
|
5041
|
+
groupId: "stage-report",
|
|
5042
|
+
parentIds: ["analyst"],
|
|
5043
|
+
injectedAncestorIds: ["fact-finder"],
|
|
5044
|
+
prompt: lines2(
|
|
5045
|
+
"Write the final report for the audience named by the Research Lead.",
|
|
5046
|
+
"Structure: recommendation, key findings, comparison, risks, sources. Short sections, plain language.",
|
|
5047
|
+
"Keep every source reference from the Fact Finder."
|
|
5048
|
+
)
|
|
5049
|
+
})
|
|
5050
|
+
]
|
|
5051
|
+
},
|
|
5052
|
+
translations: { fr: { ...PRESET_FR["research-report"], roles: ROLES_FR } },
|
|
5053
|
+
roles: ROLES
|
|
5054
|
+
},
|
|
5055
|
+
{
|
|
5056
|
+
id: "code-review",
|
|
5057
|
+
name: "Code review",
|
|
5058
|
+
icon: "ti-code",
|
|
5059
|
+
labels: {
|
|
5060
|
+
group: { en: "Team", fr: "\xC9quipe" },
|
|
5061
|
+
node: { en: "Reviewer", fr: "Relecteur" },
|
|
5062
|
+
role: { en: "Focus", fr: "Angle" },
|
|
5063
|
+
leader: { en: "Lead reviewer", fr: "Relecteur principal" }
|
|
5064
|
+
},
|
|
5065
|
+
defaultTraversalMode: "hierarchical",
|
|
5066
|
+
canChangeTraversalMode: true,
|
|
5067
|
+
initialData: {
|
|
5068
|
+
leaderId: "lead-reviewer",
|
|
5069
|
+
groups: [
|
|
5070
|
+
stage("team-lead", "Lead", 0),
|
|
5071
|
+
stage("team-security", "Security", 1, 0),
|
|
5072
|
+
stage("team-correctness", "Correctness", 1, 1),
|
|
5073
|
+
stage("team-maintainability", "Maintainability", 1, 2)
|
|
5074
|
+
],
|
|
5075
|
+
nodes: [
|
|
5076
|
+
presetNode({
|
|
5077
|
+
id: "lead-reviewer",
|
|
5078
|
+
label: "Lead Reviewer",
|
|
5079
|
+
role: "manager",
|
|
5080
|
+
groupId: "team-lead",
|
|
5081
|
+
prompt: lines2(
|
|
5082
|
+
"Identify the change to review (branch, diff or files named in the request) and summarize its intent in two sentences.",
|
|
5083
|
+
"Send each reviewer the exact scope to read and the risks specific to this change.",
|
|
5084
|
+
"In your synthesis, merge duplicate findings, drop the ones without evidence, and order the rest by severity: blocking, should fix, nit."
|
|
5085
|
+
)
|
|
5086
|
+
}),
|
|
5087
|
+
presetNode({
|
|
5088
|
+
id: "security-reviewer",
|
|
5089
|
+
label: "Security Reviewer",
|
|
5090
|
+
role: "qa",
|
|
5091
|
+
groupId: "team-security",
|
|
5092
|
+
parentIds: ["lead-reviewer"],
|
|
5093
|
+
prompt: lines2(
|
|
5094
|
+
"Review the change for security issues only: input validation, injection, authentication and authorization, secrets, unsafe defaults.",
|
|
5095
|
+
"Each finding: file and line, the attack scenario, the fix. No finding without a concrete scenario."
|
|
5096
|
+
)
|
|
5097
|
+
}),
|
|
5098
|
+
presetNode({
|
|
5099
|
+
id: "correctness-reviewer",
|
|
5100
|
+
label: "Correctness Reviewer",
|
|
5101
|
+
role: "qa",
|
|
5102
|
+
groupId: "team-correctness",
|
|
5103
|
+
parentIds: ["lead-reviewer"],
|
|
5104
|
+
prompt: lines2(
|
|
5105
|
+
"Look for bugs: wrong logic, unhandled errors, race conditions, edge cases (empty, null, large inputs), regressions in existing behaviour.",
|
|
5106
|
+
"Check that tests cover the changed behaviour and would fail without the change.",
|
|
5107
|
+
"Each finding: file and line, the input that breaks it, the expected and actual result."
|
|
5108
|
+
)
|
|
5109
|
+
}),
|
|
5110
|
+
presetNode({
|
|
5111
|
+
id: "maintainability-reviewer",
|
|
5112
|
+
label: "Maintainability Reviewer",
|
|
5113
|
+
role: "engineer",
|
|
5114
|
+
groupId: "team-maintainability",
|
|
5115
|
+
parentIds: ["lead-reviewer"],
|
|
5116
|
+
prompt: lines2(
|
|
5117
|
+
"Look for duplicated logic that already exists elsewhere in the codebase, unclear naming, dead code and changes outside the stated scope.",
|
|
5118
|
+
"Search the repository before claiming a duplicate, and name the existing function to reuse.",
|
|
5119
|
+
"Do not report style preferences that a linter would catch."
|
|
5120
|
+
)
|
|
5121
|
+
})
|
|
5122
|
+
]
|
|
5123
|
+
},
|
|
5124
|
+
translations: { fr: { ...PRESET_FR["code-review"], roles: ROLES_FR } },
|
|
5125
|
+
roles: ROLES
|
|
4082
5126
|
}
|
|
4083
5127
|
];
|
|
4084
5128
|
function listPresets() {
|
|
@@ -4087,12 +5131,13 @@ function listPresets() {
|
|
|
4087
5131
|
function getPreset(id) {
|
|
4088
5132
|
return BUILT_IN_PRESETS.find((p) => p.id === id);
|
|
4089
5133
|
}
|
|
5134
|
+
function getPresetRole(presetId, roleId, locale) {
|
|
5135
|
+
const preset = presetId ? getPreset(presetId) : void 0;
|
|
5136
|
+
if (!preset) return void 0;
|
|
5137
|
+
return (locale ? localizePreset(preset, locale) : preset).roles.find((r) => r.id === roleId);
|
|
5138
|
+
}
|
|
4090
5139
|
|
|
4091
5140
|
// ../server/src/services/scenario-runner.ts
|
|
4092
|
-
var DEFAULT_NODE_MODELS = {
|
|
4093
|
-
"claude-code": "sonnet",
|
|
4094
|
-
codex: ""
|
|
4095
|
-
};
|
|
4096
5141
|
var MAX_BUFFER = 500;
|
|
4097
5142
|
var activeBuses = /* @__PURE__ */ new Map();
|
|
4098
5143
|
var activeAbortControllers = /* @__PURE__ */ new Map();
|
|
@@ -4421,27 +5466,26 @@ function buildSystemPrompt(node, scenario) {
|
|
|
4421
5466
|
const group = scenario.groups.find((t) => t.id === node.groupId);
|
|
4422
5467
|
const manager = node.parentIds[0] ? scenario.nodes.find((p) => p.id === node.parentIds[0]) : null;
|
|
4423
5468
|
const reports = getDirectReports(scenario.nodes, node.id);
|
|
4424
|
-
const
|
|
4425
|
-
const presetRole = preset?.roles.find((r) => r.id === (node.role ?? "other"));
|
|
5469
|
+
const presetRole = getPresetRole(scenario.presetId, node.role ?? "other", scenario.locale);
|
|
4426
5470
|
const roleBehavior = presetRole?.systemPrompt ?? "";
|
|
4427
5471
|
const rolePrompt = presetRole?.prompt ?? "";
|
|
4428
|
-
const
|
|
5472
|
+
const lines3 = [
|
|
4429
5473
|
`You are ${node.label}${group ? `, member of the ${group.name} group` : ""}.`,
|
|
4430
5474
|
`Your role type: **${(node.role ?? "other").toUpperCase()}**.`,
|
|
4431
5475
|
""
|
|
4432
5476
|
];
|
|
4433
5477
|
if (roleBehavior) {
|
|
4434
|
-
|
|
5478
|
+
lines3.push("## Role Behavior (strictly enforce)", roleBehavior, "");
|
|
4435
5479
|
}
|
|
4436
5480
|
const profileSection = [node.prompt, rolePrompt].filter(Boolean).join("\n\n");
|
|
4437
|
-
|
|
5481
|
+
lines3.push("## Your Profile & Instructions", profileSection || "(No profile provided)", "");
|
|
4438
5482
|
if (manager) {
|
|
4439
|
-
|
|
5483
|
+
lines3.push(`## Reporting Line`, `You report to ${manager.label} (${manager.role ?? "other"}).`, "");
|
|
4440
5484
|
} else {
|
|
4441
|
-
|
|
5485
|
+
lines3.push(`## Position`, `You are the leader of this scenario. You coordinate all groups.`, "");
|
|
4442
5486
|
}
|
|
4443
5487
|
if (reports.length > 0) {
|
|
4444
|
-
|
|
5488
|
+
lines3.push(
|
|
4445
5489
|
`## Your Direct Reports`,
|
|
4446
5490
|
...reports.map((r) => {
|
|
4447
5491
|
const rGroup = scenario.groups.find((g) => g.id === r.groupId);
|
|
@@ -4452,7 +5496,7 @@ function buildSystemPrompt(node, scenario) {
|
|
|
4452
5496
|
);
|
|
4453
5497
|
}
|
|
4454
5498
|
if (node.canAddNode) {
|
|
4455
|
-
|
|
5499
|
+
lines3.push(
|
|
4456
5500
|
"## Hiring Capability",
|
|
4457
5501
|
"You are allowed to hire temporary contractors for this run.",
|
|
4458
5502
|
'Use exactly: <hire_person label="Jane Doe" role="engineer">Task focus prompt</hire_person>',
|
|
@@ -4461,7 +5505,7 @@ function buildSystemPrompt(node, scenario) {
|
|
|
4461
5505
|
""
|
|
4462
5506
|
);
|
|
4463
5507
|
}
|
|
4464
|
-
|
|
5508
|
+
lines3.push(
|
|
4465
5509
|
"## Output Instructions",
|
|
4466
5510
|
"Write your output clearly and in a structured format.",
|
|
4467
5511
|
"Stay strictly within your role \u2014 do not produce deliverables that belong to a different role.",
|
|
@@ -4470,9 +5514,9 @@ function buildSystemPrompt(node, scenario) {
|
|
|
4470
5514
|
);
|
|
4471
5515
|
const runeya_ai_vars = Object.entries(process.env).filter(([k]) => k.startsWith("RUNEYA_AI_")).map(([k, v]) => `${k}=${v}`).join("\n");
|
|
4472
5516
|
if (runeya_ai_vars) {
|
|
4473
|
-
|
|
5517
|
+
lines3.push("", "## Environment", "", runeya_ai_vars);
|
|
4474
5518
|
}
|
|
4475
|
-
return
|
|
5519
|
+
return lines3.join("\n");
|
|
4476
5520
|
}
|
|
4477
5521
|
function buildUserMessage(node, scenario, userRequest, managerOutput, isLeaderSynthesis, isLeaderDispatch, allOutputs) {
|
|
4478
5522
|
const parts = [];
|
|
@@ -4596,7 +5640,7 @@ function resolveNodeExecutionConfig(node, runOverrides) {
|
|
|
4596
5640
|
const crossFamily = !!runOverrides?.runnerOverride && runOverrides.runnerOverride !== baseCli;
|
|
4597
5641
|
const modelOverride = runOverrides?.modelOverride?.trim() ?? "";
|
|
4598
5642
|
const nodeModel = node.model?.trim() ?? "";
|
|
4599
|
-
const model = modelOverride || (crossFamily ?
|
|
5643
|
+
const model = modelOverride || (crossFamily ? "" : nodeModel);
|
|
4600
5644
|
return { aiCli, model };
|
|
4601
5645
|
}
|
|
4602
5646
|
function createNodeRunnerState(aiCli) {
|
|
@@ -4614,8 +5658,8 @@ async function nodeRuneyaAccess(conversationId) {
|
|
|
4614
5658
|
let injectedEnv;
|
|
4615
5659
|
if (ref?.id) {
|
|
4616
5660
|
try {
|
|
4617
|
-
const { projectStore: projectStore2 } = await import("./project-store-
|
|
4618
|
-
const { environmentResolver: environmentResolver2 } = await import("./environment-resolver-
|
|
5661
|
+
const { projectStore: projectStore2 } = await import("./project-store-BYAE4SVZ.js");
|
|
5662
|
+
const { environmentResolver: environmentResolver2 } = await import("./environment-resolver-SY36Q67E.js");
|
|
4619
5663
|
const project = await projectStore2.get(ref.orgId ? { id: ref.id, orgId: ref.orgId } : ref.id);
|
|
4620
5664
|
if (project?.activeEnvironmentId) {
|
|
4621
5665
|
const injected = await environmentResolver2.resolveAiInjectedEnv(project.activeEnvironmentId);
|
|
@@ -5490,6 +6534,7 @@ var scenarioRouter = router({
|
|
|
5490
6534
|
nodes: z16.array(ScenarioNodeSchema).min(1).max(500),
|
|
5491
6535
|
traversalMode: z16.enum(["hierarchical", "topological"]).optional(),
|
|
5492
6536
|
presetId: z16.string().max(128).optional(),
|
|
6537
|
+
locale: z16.string().max(16).optional(),
|
|
5493
6538
|
isPublished: z16.boolean().optional(),
|
|
5494
6539
|
...ScopeShape2
|
|
5495
6540
|
})).mutation(({ input }) => {
|
|
@@ -5504,6 +6549,7 @@ var scenarioRouter = router({
|
|
|
5504
6549
|
nodes: input.nodes,
|
|
5505
6550
|
traversalMode: input.traversalMode ?? "hierarchical",
|
|
5506
6551
|
presetId: input.presetId,
|
|
6552
|
+
locale: input.locale,
|
|
5507
6553
|
isPublished: input.isPublished ?? false,
|
|
5508
6554
|
createdAt: now,
|
|
5509
6555
|
updatedAt: now
|
|
@@ -5519,6 +6565,7 @@ var scenarioRouter = router({
|
|
|
5519
6565
|
nodes: z16.array(ScenarioNodeSchema).min(1).max(500).optional(),
|
|
5520
6566
|
traversalMode: z16.enum(["hierarchical", "topological"]).optional(),
|
|
5521
6567
|
presetId: z16.string().max(128).optional(),
|
|
6568
|
+
locale: z16.string().max(16).optional(),
|
|
5522
6569
|
isPublished: z16.boolean().optional(),
|
|
5523
6570
|
...ScopeShape2
|
|
5524
6571
|
})).mutation(({ input }) => updateOrThrow(
|
|
@@ -5531,6 +6578,7 @@ var scenarioRouter = router({
|
|
|
5531
6578
|
nodes: input.nodes,
|
|
5532
6579
|
traversalMode: input.traversalMode,
|
|
5533
6580
|
presetId: input.presetId,
|
|
6581
|
+
locale: input.locale,
|
|
5534
6582
|
isPublished: input.isPublished,
|
|
5535
6583
|
updatedAt: Date.now()
|
|
5536
6584
|
}, await scopeOf2(input)),
|
|
@@ -7243,11 +8291,11 @@ async function resolveScope(scope) {
|
|
|
7243
8291
|
return { mode: "local", root };
|
|
7244
8292
|
}
|
|
7245
8293
|
const serviceId = scope.slice("service:".length);
|
|
7246
|
-
const
|
|
7247
|
-
if (!
|
|
7248
|
-
const agentId = await resolveEffectiveAgentId(
|
|
8294
|
+
const service2 = await serviceStore.get(serviceId);
|
|
8295
|
+
if (!service2) throw new TRPCError21({ code: "NOT_FOUND", message: "Service introuvable" });
|
|
8296
|
+
const agentId = await resolveEffectiveAgentId(service2);
|
|
7249
8297
|
if (!agentId) throw new TRPCError21({ code: "BAD_REQUEST", message: "Aucun agent configur\xE9 pour ce service" });
|
|
7250
|
-
const cwd = await resolveWorkspaceCwd({ serviceId, override:
|
|
8298
|
+
const cwd = await resolveWorkspaceCwd({ serviceId, override: service2.docsPath?.trim() || void 0 });
|
|
7251
8299
|
return { mode: "agent", agentId, cwd };
|
|
7252
8300
|
}
|
|
7253
8301
|
async function walkLocal(root, dir, depth, counter) {
|
|
@@ -7397,11 +8445,11 @@ var wikiRouter = router({
|
|
|
7397
8445
|
return { ok: true };
|
|
7398
8446
|
}
|
|
7399
8447
|
const serviceId = input.scope.slice("service:".length);
|
|
7400
|
-
const
|
|
7401
|
-
if (!
|
|
7402
|
-
const agentId = await resolveEffectiveAgentId(
|
|
8448
|
+
const service2 = await serviceStore.get(serviceId);
|
|
8449
|
+
if (!service2) throw new TRPCError21({ code: "NOT_FOUND", message: "Service introuvable" });
|
|
8450
|
+
const agentId = await resolveEffectiveAgentId(service2);
|
|
7403
8451
|
if (!agentId) throw new TRPCError21({ code: "BAD_REQUEST", message: "Aucun agent configur\xE9" });
|
|
7404
|
-
const cwd = await resolveWorkspaceCwd({ serviceId, override:
|
|
8452
|
+
const cwd = await resolveWorkspaceCwd({ serviceId, override: service2.docsPath?.trim() || void 0 });
|
|
7405
8453
|
return agentManager.agentMutation(agentId, "wiki.ensureRoot", { cwd });
|
|
7406
8454
|
}),
|
|
7407
8455
|
delete: protectedProcedure.input(z26.object({ scope: SCOPE_SCHEMA, path: REL_PATH_SCHEMA })).mutation(async ({ input }) => {
|
|
@@ -10054,7 +11102,7 @@ async function runLegacyMigration(dataDir) {
|
|
|
10054
11102
|
for (const [name, legacy] of Object.entries(legacyServices)) {
|
|
10055
11103
|
const serviceId = serviceIdMap[name];
|
|
10056
11104
|
if (!serviceId) continue;
|
|
10057
|
-
const
|
|
11105
|
+
const service2 = runeServices.find((s) => s.id === serviceId);
|
|
10058
11106
|
const svcEnvs = legacy.envs || {};
|
|
10059
11107
|
for (const [envName, vars] of Object.entries(svcEnvs)) {
|
|
10060
11108
|
if (!vars || typeof vars !== "object" || Object.keys(vars).length === 0) continue;
|
|
@@ -10068,7 +11116,7 @@ async function runLegacyMigration(dataDir) {
|
|
|
10068
11116
|
svcScopedEnv = {
|
|
10069
11117
|
id: randomUUID9(),
|
|
10070
11118
|
projectId: projectMonoId,
|
|
10071
|
-
name: `${
|
|
11119
|
+
name: `${service2?.name || name} (${globalEnv.name})`,
|
|
10072
11120
|
scope: "service",
|
|
10073
11121
|
reference: serviceId,
|
|
10074
11122
|
activateOn: globalEnvId,
|
|
@@ -10100,7 +11148,7 @@ async function runLegacyMigration(dataDir) {
|
|
|
10100
11148
|
for (const [serviceName, envOverrides] of Object.entries(legacyServiceOverrides)) {
|
|
10101
11149
|
const serviceId = serviceIdMap[serviceName];
|
|
10102
11150
|
if (!serviceId) continue;
|
|
10103
|
-
const
|
|
11151
|
+
const service2 = runeServices.find((s) => s.id === serviceId);
|
|
10104
11152
|
for (const [envName, vars] of Object.entries(envOverrides)) {
|
|
10105
11153
|
const globalEnvId = envIdMap[envName];
|
|
10106
11154
|
const globalEnv = runeEnvs.find((e) => e.id === globalEnvId);
|
|
@@ -10112,7 +11160,7 @@ async function runLegacyMigration(dataDir) {
|
|
|
10112
11160
|
svcScopedEnv = {
|
|
10113
11161
|
id: randomUUID9(),
|
|
10114
11162
|
projectId: projectMonoId,
|
|
10115
|
-
name: `${
|
|
11163
|
+
name: `${service2?.name || serviceName} (${globalEnv.name})`,
|
|
10116
11164
|
scope: "service",
|
|
10117
11165
|
reference: serviceId,
|
|
10118
11166
|
activateOn: globalEnvId,
|
|
@@ -10377,7 +11425,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
10377
11425
|
console.warn(`[override-migration] No matching service for "${serviceName}" \u2014 skipping service overrides`);
|
|
10378
11426
|
continue;
|
|
10379
11427
|
}
|
|
10380
|
-
const
|
|
11428
|
+
const service2 = servicesRaw.find((s) => s["id"] === serviceId);
|
|
10381
11429
|
for (const [envName, vars] of Object.entries(data)) {
|
|
10382
11430
|
const globalEnvId = findEnvId(envName);
|
|
10383
11431
|
if (!globalEnvId || !vars || typeof vars !== "object") continue;
|
|
@@ -10390,7 +11438,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
10390
11438
|
svcScopedEnv = {
|
|
10391
11439
|
id: randomUUID9(),
|
|
10392
11440
|
projectId: globalEnv["projectId"],
|
|
10393
|
-
name: `${
|
|
11441
|
+
name: `${service2?.["name"] || serviceName} (${globalEnv["name"]})`,
|
|
10394
11442
|
scope: "service",
|
|
10395
11443
|
reference: serviceId,
|
|
10396
11444
|
activateOn: globalEnvId,
|
|
@@ -11636,7 +12684,7 @@ async function createLocalServer() {
|
|
|
11636
12684
|
]);
|
|
11637
12685
|
console.log("[server] Shutdown complete");
|
|
11638
12686
|
};
|
|
11639
|
-
const { initCompanion } = await import("./companion-
|
|
12687
|
+
const { initCompanion } = await import("./companion-H24L2MGY.js");
|
|
11640
12688
|
initCompanion();
|
|
11641
12689
|
return { app, server, wss, shutdown };
|
|
11642
12690
|
}
|
|
@@ -11701,10 +12749,10 @@ async function unlockIfNeeded() {
|
|
|
11701
12749
|
async function pullEnv(opts) {
|
|
11702
12750
|
await unlockIfNeeded();
|
|
11703
12751
|
const services = await serviceStore.list();
|
|
11704
|
-
const
|
|
12752
|
+
const service2 = services.find(
|
|
11705
12753
|
(s) => s.id === opts.service || s.name === opts.service
|
|
11706
12754
|
);
|
|
11707
|
-
if (!
|
|
12755
|
+
if (!service2) {
|
|
11708
12756
|
const available = services.map((s) => s.name).join(", ");
|
|
11709
12757
|
throw new PullEnvError(`service "${opts.service}" not found. Available: ${available || "(none)"}`, 1);
|
|
11710
12758
|
}
|
|
@@ -11717,7 +12765,7 @@ async function pullEnv(opts) {
|
|
|
11717
12765
|
throw new PullEnvError(`environment "${opts.environment}" not found. Available: ${available || "(none)"}`, 1);
|
|
11718
12766
|
}
|
|
11719
12767
|
const { env: env2 } = await environmentResolver.resolveForService({
|
|
11720
|
-
serviceId:
|
|
12768
|
+
serviceId: service2.id,
|
|
11721
12769
|
activeEnvironmentId: globalEnv.id
|
|
11722
12770
|
});
|
|
11723
12771
|
return Object.entries(env2).map(([key, value]) => `${key}=${value}`).join("\n");
|
|
@@ -11727,20 +12775,20 @@ async function pullEnv(opts) {
|
|
|
11727
12775
|
async function listTrayServices() {
|
|
11728
12776
|
const [all, processes] = await Promise.all([serviceStore.list(), listAllProcesses()]);
|
|
11729
12777
|
const byServiceId = new Map(processes.map((p) => [p.serviceId, p]));
|
|
11730
|
-
const services = all.map((
|
|
11731
|
-
const status = byServiceId.get(
|
|
12778
|
+
const services = all.map((service2) => {
|
|
12779
|
+
const status = byServiceId.get(service2.id);
|
|
11732
12780
|
return {
|
|
11733
|
-
id:
|
|
11734
|
-
name:
|
|
11735
|
-
agentId: status?.agentId ??
|
|
12781
|
+
id: service2.id,
|
|
12782
|
+
name: service2.name,
|
|
12783
|
+
agentId: status?.agentId ?? service2.agentId ?? null,
|
|
11736
12784
|
running: status?.state === "running" || status?.state === "starting",
|
|
11737
12785
|
failed: status?.state === "errored" || status?.healthStatus === "unhealthy",
|
|
11738
|
-
url: primaryServiceLink(
|
|
12786
|
+
url: primaryServiceLink(service2, "localhost")
|
|
11739
12787
|
};
|
|
11740
12788
|
});
|
|
11741
12789
|
const owned = await currentProjectServiceIds();
|
|
11742
|
-
if (owned) return services.filter((
|
|
11743
|
-
return services.filter((
|
|
12790
|
+
if (owned) return services.filter((service2) => owned.has(service2.id));
|
|
12791
|
+
return services.filter((service2) => service2.running || service2.failed);
|
|
11744
12792
|
}
|
|
11745
12793
|
async function currentProjectServiceIds() {
|
|
11746
12794
|
const ref = getCurrentProject();
|
|
@@ -12092,4 +13140,4 @@ export {
|
|
|
12092
13140
|
stopProcess,
|
|
12093
13141
|
userPrefix
|
|
12094
13142
|
};
|
|
12095
|
-
//# sourceMappingURL=src-
|
|
13143
|
+
//# sourceMappingURL=src-OENXLZKQ.js.map
|