@runeya/runeya 2.0.144 → 2.0.146
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 +33 -22
- package/agent/index.js.map +1 -1
- package/agent-manager-R7BPQO6D.js +11 -0
- package/chat-LPML22J5.js +24 -0
- package/{chunk-7L6AQUBR.js → chunk-4LJQIQMN.js} +6 -2
- package/{chunk-7L6AQUBR.js.map → chunk-4LJQIQMN.js.map} +1 -1
- package/{chunk-7HIPFSOA.js → chunk-57P45FNY.js} +11 -3
- package/chunk-57P45FNY.js.map +1 -0
- package/chunk-6IBPK6UE.js +1063 -0
- package/chunk-6IBPK6UE.js.map +1 -0
- package/{chunk-GXE5TLLJ.js → chunk-KV4GJKXU.js} +17 -17
- package/{chunk-XAFOP677.js → chunk-MZSDTA4A.js} +480 -233
- package/chunk-MZSDTA4A.js.map +1 -0
- package/{chunk-UR3HL373.js → chunk-NPMSBYXC.js} +8 -8
- package/{chunk-P73PTVII.js → chunk-SEPAURTQ.js} +369 -1282
- package/chunk-SEPAURTQ.js.map +1 -0
- package/{chunk-NSS47H26.js → chunk-UD42LACH.js} +348 -78
- package/chunk-UD42LACH.js.map +1 -0
- package/{chunk-IXO5KIO5.js → chunk-VPSQJOSN.js} +23 -2
- package/{chunk-IXO5KIO5.js.map → chunk-VPSQJOSN.js.map} +1 -1
- package/{companion-2LHKU577.js → companion-W3UMZWGH.js} +11 -7
- package/{desktop-installer-page-6JDSXK2E.js → desktop-installer-page-I5FHFDES.js} +11 -8
- package/desktop-installer-page-I5FHFDES.js.map +1 -0
- package/{desktop-launcher-YPNRQMIS.js → desktop-launcher-GD4QPM66.js} +3 -3
- package/external-NMKQPROK.js +387 -0
- package/external-NMKQPROK.js.map +1 -0
- package/index.js +34 -12
- package/index.js.map +1 -1
- package/{install-gate-2NNH7RM2.js → install-gate-PVMGJDWE.js} +2 -2
- package/mcp-server/external.d.ts +44 -0
- package/mcp-server/external.js +2679 -0
- package/mcp-server/external.js.map +1 -0
- package/mcp-server/index.js +142 -40
- package/mcp-server/index.js.map +1 -1
- package/mcp-server/launch.d.ts +19 -1
- package/mcp-server/launch.js +20 -0
- package/mcp-server/launch.js.map +1 -1
- package/package.json +1 -1
- package/settings-manager-XPLBO35P.js +10 -0
- package/src-DCCEUWE6.js +385 -0
- package/{src-5TEXF3SU.js → src-LEDGW5KP.js} +1029 -536
- package/src-LEDGW5KP.js.map +1 -0
- package/{vault-resolver-VK6W5J6W.js → vault-resolver-E7KPKA5C.js} +3 -2
- package/vault-resolver-E7KPKA5C.js.map +1 -0
- package/web/assets/{AgentScalarChatInterface.vue-B-SjOsdj.js → AgentScalarChatInterface.vue-BYszptaB.js} +1 -1
- package/web/assets/{AgentTerminalPage-JzC8DUgu.js → AgentTerminalPage-C3TJ1NL9.js} +1 -1
- package/web/assets/{AiChatModals-D1928AxG.js → AiChatModals-D3scRE3S.js} +1 -1
- package/web/assets/AppLayout-BMQUjPKe.js +1 -0
- package/web/assets/{AppLayout-8sBPr3od.css → AppLayout-tsw5Ow0w.css} +1 -1
- package/web/assets/{AuditPage-BZIJ3_Kr.js → AuditPage-CKcExBws.js} +1 -1
- package/web/assets/{CloudAccountPage-DBv470sT.js → CloudAccountPage-B6oPg0BZ.js} +1 -1
- package/web/assets/{CloudMessagingPage-qCI8-UDL.js → CloudMessagingPage-C5fwVe-F.js} +1 -1
- package/web/assets/DashboardPage-9RV7sx3e.js +1 -0
- package/web/assets/{DashboardPage-D9-PpC3F.css → DashboardPage-FvNuC_e4.css} +1 -1
- package/web/assets/{DirectoryPickerDialog-B5DvDfQP.js → DirectoryPickerDialog-C06BXyfJ.js} +1 -1
- package/web/assets/{EnvironmentForm-Bw8Djnqm.js → EnvironmentForm-CAvDoira.js} +1 -1
- package/web/assets/{EnvironmentFormPage-B59uiYtp.js → EnvironmentFormPage-BmAxhN-m.js} +1 -1
- package/web/assets/{EnvironmentListPage-W9zLDZAg.js → EnvironmentListPage-B8uATPBI.js} +1 -1
- package/web/assets/KanbanBoardPage-CQsOkRUf.js +4 -0
- package/web/assets/KanbanBoardPage-eHmsrFGA.css +1 -0
- package/web/assets/{KanbanListPage-Bn9k8Rpc.js → KanbanListPage-CWZqkjD6.js} +1 -1
- package/web/assets/{LaunchProjectPage-Dc7v1UjQ.js → LaunchProjectPage-saSmC7Pr.js} +1 -1
- package/web/assets/LaunchServicesPage-BkKyLMEz.js +1 -0
- package/web/assets/LaunchServicesPage-DoLDPqQq.css +1 -0
- package/web/assets/{LaunchShell-LonTJpb3.js → LaunchShell-DUrSunB4.js} +1 -1
- package/web/assets/{LogViewer-DkuqWYkQ.js → LogViewer-CZBYkH9J.js} +1 -1
- package/web/assets/{OrgKeyPrompt-By1VjlSN.js → OrgKeyPrompt-DzQ7pwbs.js} +1 -1
- package/web/assets/{ProcessControls-C0skzKGL.js → ProcessControls-BEeoNlNV.js} +1 -1
- package/web/assets/{ProcessDetailPage-BvPX6z_X.js → ProcessDetailPage-CQgu5uKm.js} +1 -1
- package/web/assets/{ProjectCreateDialog-C4o9u15L.js → ProjectCreateDialog-BolrhRD-.js} +1 -1
- package/web/assets/{ProjectLocationGate-BJ1CSQt0.js → ProjectLocationGate-DhMVdIjN.js} +1 -1
- package/web/assets/{ProjectPublishDialog-Cp-zXdGm.js → ProjectPublishDialog-DsZNWrfz.js} +1 -1
- package/web/assets/{RandomJobTestPage-DF4a1U13.js → RandomJobTestPage-BUS2Ty6-.js} +1 -1
- package/web/assets/ScenarioEditorPage-MIAGh2us.js +14 -0
- package/web/assets/{SendToChatDialog-Dg2SHkVD.js → SendToChatDialog-BxWsyv29.js} +1 -1
- package/web/assets/{ServiceControlsBar-q2VHWaxK.js → ServiceControlsBar-DqDPAZt7.js} +1 -1
- package/web/assets/ServiceDetailPage-hkSAzZ-l.js +2 -0
- package/web/assets/{ServiceFormPage-tT_n7WUy.js → ServiceFormPage-DXqhqXg8.js} +1 -1
- package/web/assets/SettingsPage-4pKUgKPm.css +1 -0
- package/web/assets/SettingsPage-DS2YhMIM.js +2086 -0
- package/web/assets/{UnlockPage-BKAdMJkb.js → UnlockPage-s8SgVcKk.js} +1 -1
- package/web/assets/{VaultMigrationPage-D9KUTTss.js → VaultMigrationPage-s0b44MDM.js} +1 -1
- package/web/assets/{VersionBadge-moKP5bAv.js → VersionBadge-BmArk24p.js} +1 -1
- package/web/assets/{WikiPage-hLUndDxo.js → WikiPage-DADu8WUA.js} +1 -1
- package/web/assets/{WikiView-rrjXRR72.js → WikiView-DtGwIt_Q.js} +1 -1
- package/web/assets/{add-scalar-classes-CBfRr8B2.js → add-scalar-classes-dWEWPlFD.js} +2 -2
- package/web/assets/{agent.store-B3dVemmT.js → agent.store-CKLAkF9a.js} +1 -1
- package/web/assets/app-mode-BVpTuh0i.js +1 -0
- package/web/assets/auth-Cg9BWTfK.js +2 -0
- package/web/assets/{cloud-chat.store-Wg1poFem.js → cloud-chat.store-b-BHGz7I.js} +1 -1
- package/web/assets/{cloud-client-DQlUaoAw.js → cloud-client-D_zCiW0s.js} +2 -2
- package/web/assets/{cloud-session-DRUqcSGP.js → cloud-session-DOaDpZTy.js} +2 -2
- package/web/assets/dist-N4nrnbnA.js +1 -0
- package/web/assets/{editor.store-SoH48ux2.js → editor.store-DCAZSeVG.js} +1 -1
- package/web/assets/i18n-D0afQEGs.js +1 -0
- package/web/assets/{index-D_x2s8Ut.js → index-D8VRbyoP.js} +101 -101
- package/web/assets/index-DsezNbSM.css +1 -0
- package/web/assets/{modal-CpsVK_dA.js → modal-qYgTMkYb.js} +1 -1
- package/web/assets/{project-launch.store-C3fZeRGb.js → project-launch.store-y7JBMNiE.js} +1 -1
- package/web/assets/{project.store-BEk4fciH.js → project.store-DGJr0Qr9.js} +1 -1
- package/web/assets/{scenario.store-D-JrRiVO.js → scenario.store-YWHL2_wu.js} +3 -3
- package/web/assets/{service.store-B5uYZtyM.js → service.store-5jWsJxPx.js} +1 -1
- package/web/assets/{settings-scope-Blnwj3rR.js → settings-scope-Bv7QGPrt.js} +1 -1
- package/web/assets/{settings.store-Bo3FYs1o.js → settings.store-bEsB7oKb.js} +1 -1
- package/web/assets/{src-CAwAaB5j.js → src-C-D_y7ou.js} +1 -1
- package/web/assets/{src-DValZNJU.js → src-Dnwk6NpV.js} +5 -5
- package/web/assets/src-g1DRo8xZ.css +1 -0
- package/web/assets/{trpc-DbsE5GvQ.js → trpc-Drabzwpd.js} +3 -3
- package/web/assets/{useCloudOrg-DygUBG1a.js → useCloudOrg-BAQEtFPl.js} +1 -1
- package/web/assets/{useEnvVarAutocomplete-DmYNOXgd.js → useEnvVarAutocomplete-BqGTODUv.js} +1 -1
- package/web/assets/{useProjectCatalog-D2mHB7dg.js → useProjectCatalog-yocjIKt6.js} +1 -1
- package/web/assets/{useProjectCloudOrg-avTCVold.js → useProjectCloudOrg-CEN9-_OA.js} +1 -1
- package/web/assets/{useServiceUrlHost-Q3fzGox3.js → useServiceUrlHost-BuoPEXZX.js} +1 -1
- package/web/assets/{vue-draggable-plus-WgrMXXmE.js → vue-draggable-plus-DX4rTBiu.js} +1 -1
- package/web/index.html +19 -18
- package/agent-manager-M4NA5YFD.js +0 -11
- package/chat-X3X527EX.js +0 -23
- package/chunk-7HIPFSOA.js.map +0 -1
- package/chunk-NSS47H26.js.map +0 -1
- package/chunk-P73PTVII.js.map +0 -1
- package/chunk-XAFOP677.js.map +0 -1
- package/desktop-installer-page-6JDSXK2E.js.map +0 -1
- package/settings-manager-32SVMAFN.js +0 -10
- package/src-5TEXF3SU.js.map +0 -1
- package/web/assets/AppLayout-CVQIBYqg.js +0 -1
- package/web/assets/DashboardPage-D0UZM0mr.js +0 -1
- package/web/assets/KanbanBoardPage-DRACMk_D.css +0 -1
- package/web/assets/KanbanBoardPage-DwPqoJDJ.js +0 -4
- package/web/assets/LaunchServicesPage-CXUS9O3y.js +0 -1
- package/web/assets/LaunchServicesPage-DJDIN8HU.css +0 -1
- package/web/assets/ScenarioEditorPage-Dl-gEkJI.js +0 -14
- package/web/assets/ServiceDetailPage-CJ8WaFod.js +0 -2
- package/web/assets/SettingsPage-CWakkv0V.js +0 -2086
- package/web/assets/SettingsPage-aGSxZw1n.css +0 -1
- package/web/assets/auth-BCrvnP1U.js +0 -2
- package/web/assets/dist-DoChtT9t.js +0 -1
- package/web/assets/i18n-BszFg0ko.js +0 -1
- package/web/assets/index-C_JV7fYy.css +0 -1
- package/web/assets/src-DuBXN1hu.css +0 -1
- /package/{agent-manager-M4NA5YFD.js.map → agent-manager-R7BPQO6D.js.map} +0 -0
- /package/{chat-X3X527EX.js.map → chat-LPML22J5.js.map} +0 -0
- /package/{chunk-GXE5TLLJ.js.map → chunk-KV4GJKXU.js.map} +0 -0
- /package/{chunk-UR3HL373.js.map → chunk-NPMSBYXC.js.map} +0 -0
- /package/{companion-2LHKU577.js.map → companion-W3UMZWGH.js.map} +0 -0
- /package/{desktop-launcher-YPNRQMIS.js.map → desktop-launcher-GD4QPM66.js.map} +0 -0
- /package/{install-gate-2NNH7RM2.js.map → install-gate-PVMGJDWE.js.map} +0 -0
- /package/{settings-manager-32SVMAFN.js.map → settings-manager-XPLBO35P.js.map} +0 -0
- /package/{vault-resolver-VK6W5J6W.js.map → src-DCCEUWE6.js.map} +0 -0
|
@@ -1,10 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RUNEYA_CAPABILITIES,
|
|
3
|
+
applyProjectAnchor,
|
|
4
|
+
buildAnthropicTools,
|
|
5
|
+
buildOpenAITools,
|
|
6
|
+
buildToolSafetyInstruction,
|
|
7
|
+
runCapability,
|
|
8
|
+
toRawParams
|
|
9
|
+
} from "./chunk-6IBPK6UE.js";
|
|
1
10
|
import {
|
|
2
11
|
settingsManager
|
|
3
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-NPMSBYXC.js";
|
|
4
13
|
import {
|
|
5
14
|
COMPANION_SIGNATURE,
|
|
6
15
|
activeSessionRegistry,
|
|
7
16
|
claudeSessionExists,
|
|
17
|
+
companionCreateDefaults,
|
|
18
|
+
companionInstructions,
|
|
19
|
+
companionSettings,
|
|
8
20
|
companionSkips,
|
|
9
21
|
companionSystemNote,
|
|
10
22
|
companionThinkingIds,
|
|
@@ -35,7 +47,7 @@ import {
|
|
|
35
47
|
stopCompanion,
|
|
36
48
|
syncConversationFromClaudeTranscript,
|
|
37
49
|
verifyJwt
|
|
38
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-UD42LACH.js";
|
|
39
51
|
import {
|
|
40
52
|
StoreDiskCoordinator,
|
|
41
53
|
agentManager,
|
|
@@ -54,7 +66,11 @@ import {
|
|
|
54
66
|
recordLocalRemoval,
|
|
55
67
|
refsOfProjectId,
|
|
56
68
|
serviceStore
|
|
57
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-KV4GJKXU.js";
|
|
70
|
+
import {
|
|
71
|
+
isCliAvailable,
|
|
72
|
+
resolveCliInvocation
|
|
73
|
+
} from "./chunk-OZBSOSAS.js";
|
|
58
74
|
import {
|
|
59
75
|
atomicWriteJsonSecure,
|
|
60
76
|
atomicWriteSecure,
|
|
@@ -65,12 +81,22 @@ import {
|
|
|
65
81
|
renameWithRetry,
|
|
66
82
|
resolveConversationRunDir,
|
|
67
83
|
wasRead
|
|
68
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-4LJQIQMN.js";
|
|
85
|
+
import {
|
|
86
|
+
allVaultRoots,
|
|
87
|
+
env,
|
|
88
|
+
keyedFilePath,
|
|
89
|
+
legacyMachineFilePath,
|
|
90
|
+
listOrgVaults,
|
|
91
|
+
machineFilePath,
|
|
92
|
+
machineRoot,
|
|
93
|
+
orgVaultRoot,
|
|
94
|
+
vaultIdOfRoot
|
|
95
|
+
} from "./chunk-VPSQJOSN.js";
|
|
69
96
|
import {
|
|
70
97
|
AGENT_STOP_FETCH_TIMEOUT,
|
|
71
98
|
ApiKeysFileSchema,
|
|
72
|
-
|
|
73
|
-
BootstrapCommandSchema,
|
|
99
|
+
CLAUDE_CODE_MODELS,
|
|
74
100
|
DockerConfigSchema,
|
|
75
101
|
HealthCheckSchema,
|
|
76
102
|
JSLogParserSchema,
|
|
@@ -80,14 +106,12 @@ import {
|
|
|
80
106
|
RestartStrategySchema,
|
|
81
107
|
ScenarioSchema,
|
|
82
108
|
ServiceCommandSchema,
|
|
83
|
-
ServiceConfigSchema,
|
|
84
109
|
ServiceShortcutSchema,
|
|
85
110
|
ambiguousServiceSlugs,
|
|
86
111
|
crossServiceValues,
|
|
87
112
|
findUnresolvedReferences,
|
|
88
113
|
interpolateBuiltinsInEnv,
|
|
89
114
|
isSharedWithAi,
|
|
90
|
-
maskLogSourceSecrets,
|
|
91
115
|
nativeParsers,
|
|
92
116
|
restoreLogSourceSecrets,
|
|
93
117
|
servicePortValues,
|
|
@@ -95,25 +119,10 @@ import {
|
|
|
95
119
|
serviceUrlValues,
|
|
96
120
|
urlHostFor,
|
|
97
121
|
withDeprecatedAliases
|
|
98
|
-
} from "./chunk-
|
|
99
|
-
import {
|
|
100
|
-
allVaultRoots,
|
|
101
|
-
env,
|
|
102
|
-
keyedFilePath,
|
|
103
|
-
legacyMachineFilePath,
|
|
104
|
-
listOrgVaults,
|
|
105
|
-
machineFilePath,
|
|
106
|
-
machineRoot,
|
|
107
|
-
orgVaultRoot,
|
|
108
|
-
vaultIdOfRoot
|
|
109
|
-
} from "./chunk-IXO5KIO5.js";
|
|
110
|
-
import {
|
|
111
|
-
isCliAvailable,
|
|
112
|
-
resolveCliInvocation
|
|
113
|
-
} from "./chunk-OZBSOSAS.js";
|
|
122
|
+
} from "./chunk-MZSDTA4A.js";
|
|
114
123
|
|
|
115
124
|
// ../server/src/trpc/routers/chat.ts
|
|
116
|
-
import { z as
|
|
125
|
+
import { z as z6 } from "zod";
|
|
117
126
|
import Anthropic2 from "@anthropic-ai/sdk";
|
|
118
127
|
import OpenAI2 from "openai";
|
|
119
128
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -174,6 +183,16 @@ function codexMcpArgs(env2) {
|
|
|
174
183
|
}
|
|
175
184
|
return ["-c", `mcp_servers.runeya={${fields.join(",")}}`];
|
|
176
185
|
}
|
|
186
|
+
function codexRuneyaMcpArgs(env2, build = codexMcpArgs, warn = console.warn) {
|
|
187
|
+
const disabled = ["-c", "mcp_servers.runeya.enabled=false"];
|
|
188
|
+
if (!env2.RUNEYA_API_TOKEN) return disabled;
|
|
189
|
+
try {
|
|
190
|
+
return build(env2);
|
|
191
|
+
} catch (err) {
|
|
192
|
+
warn(`[codex] Failed to resolve MCP server path: ${err.message}`);
|
|
193
|
+
return disabled;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
177
196
|
function tomlString(value) {
|
|
178
197
|
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/[\u0000-\u001f\u007f]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
|
179
198
|
return `"${escaped}"`;
|
|
@@ -496,7 +515,8 @@ var router = t.router;
|
|
|
496
515
|
var createCallerFactory = t.createCallerFactory;
|
|
497
516
|
var publicProcedure = t.procedure;
|
|
498
517
|
var API_KEY_REGEX = /^[0-9a-f]{64}$/i;
|
|
499
|
-
var
|
|
518
|
+
var MCP_CLIENT_ROUTES = /* @__PURE__ */ new Set([...RUNEYA_CAPABILITIES.map((c) => c.route), "project.containing"]);
|
|
519
|
+
var authMiddleware = t.middleware(async ({ ctx, next, path }) => {
|
|
500
520
|
const { authorization } = ctx;
|
|
501
521
|
if (authorization?.startsWith("Bearer ") && API_KEY_REGEX.test(authorization.slice(7))) {
|
|
502
522
|
if (!hasEncryptionKey()) {
|
|
@@ -516,15 +536,24 @@ var authMiddleware = t.middleware(async ({ ctx, next }) => {
|
|
|
516
536
|
throw new TRPCError({ code: "UNAUTHORIZED", message: "Missing or invalid Authorization header" });
|
|
517
537
|
}
|
|
518
538
|
const token = authorization.slice(7);
|
|
539
|
+
let mcpClientId = null;
|
|
519
540
|
try {
|
|
520
|
-
await verifyJwt(token);
|
|
541
|
+
mcpClientId = (await verifyJwt(token, { allowMcp: true })).mcpClientId ?? null;
|
|
521
542
|
} catch {
|
|
522
543
|
throw new TRPCError({ code: "UNAUTHORIZED", message: "Invalid or expired token" });
|
|
523
544
|
}
|
|
524
|
-
|
|
545
|
+
if (mcpClientId && !MCP_CLIENT_ROUTES.has(path)) {
|
|
546
|
+
throw new TRPCError({ code: "FORBIDDEN", message: "An MCP client cannot call this route." });
|
|
547
|
+
}
|
|
548
|
+
return next({ ctx: { ...ctx, callerType: "app", apiKey: null, mcpClientId } });
|
|
525
549
|
});
|
|
526
550
|
var protectedProcedure = t.procedure.use(authMiddleware);
|
|
527
551
|
var LOOPBACK = /* @__PURE__ */ new Set(["127.0.0.1", "::1", "::ffff:127.0.0.1"]);
|
|
552
|
+
function requireLoopback(ctx) {
|
|
553
|
+
if (!ctx.remoteAddress || !LOOPBACK.has(ctx.remoteAddress)) {
|
|
554
|
+
throw new TRPCError({ code: "FORBIDDEN", message: "This route only answers the local machine." });
|
|
555
|
+
}
|
|
556
|
+
}
|
|
528
557
|
async function requireLoopbackOrToken(ctx) {
|
|
529
558
|
if (ctx.remoteAddress && LOOPBACK.has(ctx.remoteAddress)) return;
|
|
530
559
|
if (isCiMode()) return;
|
|
@@ -541,6 +570,11 @@ async function requireLoopbackOrToken(ctx) {
|
|
|
541
570
|
throw new TRPCError({ code: "UNAUTHORIZED", message: "Invalid or expired token" });
|
|
542
571
|
}
|
|
543
572
|
}
|
|
573
|
+
function requireHuman(ctx) {
|
|
574
|
+
if (isCiMode() || ctx.callerType !== "app" || ctx.mcpClientId) {
|
|
575
|
+
throw new TRPCError({ code: "FORBIDDEN", message: "Only the Runeya app can do this." });
|
|
576
|
+
}
|
|
577
|
+
}
|
|
544
578
|
function requireServiceAction(ctx, serviceId, action) {
|
|
545
579
|
if (ctx.callerType !== "api") return;
|
|
546
580
|
const perm = ctx.apiKey.scopes.services.find((p) => p.serviceId === serviceId);
|
|
@@ -1160,8 +1194,8 @@ var EnvironmentResolver = class {
|
|
|
1160
1194
|
return secretKeys;
|
|
1161
1195
|
}
|
|
1162
1196
|
interpolatesSecretKey(rawValue, ctxSecretKeys) {
|
|
1163
|
-
const
|
|
1164
|
-
return
|
|
1197
|
+
const refs = [...rawValue.matchAll(/\{\{environment\.([^}]+)\}\}/g)].map((m) => m[1]);
|
|
1198
|
+
return refs.some((ref) => ctxSecretKeys.has(ref));
|
|
1165
1199
|
}
|
|
1166
1200
|
/**
|
|
1167
1201
|
* Build the interpolation context for an environment.
|
|
@@ -1364,1013 +1398,6 @@ var EnvironmentResolver = class {
|
|
|
1364
1398
|
};
|
|
1365
1399
|
var environmentResolver = new EnvironmentResolver();
|
|
1366
1400
|
|
|
1367
|
-
// ../../packages/ai-capabilities/src/capabilities.ts
|
|
1368
|
-
import { z as z3 } from "zod";
|
|
1369
|
-
function toList(raw) {
|
|
1370
|
-
if (!raw) return [];
|
|
1371
|
-
const text = raw.trim();
|
|
1372
|
-
if (text.startsWith("[")) {
|
|
1373
|
-
try {
|
|
1374
|
-
const parsed = JSON.parse(text);
|
|
1375
|
-
if (Array.isArray(parsed)) return parsed.map((v) => String(v).trim()).filter(Boolean);
|
|
1376
|
-
} catch {
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
return text.split(",").map((v) => v.trim().replace(/^["'[]+|["'\]]+$/g, "")).filter(Boolean);
|
|
1380
|
-
}
|
|
1381
|
-
function clearable(raw, parse, key) {
|
|
1382
|
-
if (raw === void 0) return {};
|
|
1383
|
-
const text = String(raw).trim();
|
|
1384
|
-
if (!text || text === "null") return { [key]: null };
|
|
1385
|
-
return { [key]: parse(text) };
|
|
1386
|
-
}
|
|
1387
|
-
function gitTarget(p) {
|
|
1388
|
-
return {
|
|
1389
|
-
...p.serviceId ? { serviceId: p.serviceId } : {},
|
|
1390
|
-
...p.projectId ? { projectId: p.projectId } : {},
|
|
1391
|
-
...p.agentId ? { agentId: p.agentId } : {},
|
|
1392
|
-
...p.orgId ? { orgId: p.orgId } : {}
|
|
1393
|
-
};
|
|
1394
|
-
}
|
|
1395
|
-
var toBool = (raw) => raw.trim().toLowerCase() === "true";
|
|
1396
|
-
var newId = () => globalThis.crypto.randomUUID();
|
|
1397
|
-
function listItem(raw) {
|
|
1398
|
-
try {
|
|
1399
|
-
return JSON.parse(raw);
|
|
1400
|
-
} catch {
|
|
1401
|
-
return raw;
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
function parseTyped(name, schema, raw) {
|
|
1405
|
-
if (raw === void 0) return void 0;
|
|
1406
|
-
let result = raw.trim() === "null" ? schema.safeParse(null) : schema.safeParse(raw);
|
|
1407
|
-
if (!result.success && raw.trim() === "null") result = schema.safeParse(raw);
|
|
1408
|
-
if (!result.success) {
|
|
1409
|
-
const text = raw.trim();
|
|
1410
|
-
const json = listItem(text);
|
|
1411
|
-
if (json !== text) result = schema.safeParse(json);
|
|
1412
|
-
if (!result.success && !/^[[{]/.test(text)) {
|
|
1413
|
-
const list = schema.safeParse(toList(text).map(listItem));
|
|
1414
|
-
if (list.success) result = list;
|
|
1415
|
-
}
|
|
1416
|
-
}
|
|
1417
|
-
if (!result.success) throw new Error(`${name}: ${z3.prettifyError(result.error)}`);
|
|
1418
|
-
return result.data;
|
|
1419
|
-
}
|
|
1420
|
-
function withIds(items) {
|
|
1421
|
-
return items.map((item) => ({ ...item, id: item.id || newId() }));
|
|
1422
|
-
}
|
|
1423
|
-
var optionalId = (schema) => schema.extend({ id: z3.string().min(1).max(64).optional() });
|
|
1424
|
-
var DockerConfigInput = DockerConfigSchema.extend({
|
|
1425
|
-
bootstrapCommands: z3.array(optionalId(BootstrapCommandSchema)).max(20).default([])
|
|
1426
|
-
}).refine((c) => !!c.image !== !!c.dockerfile, {
|
|
1427
|
-
message: 'dockerConfig needs exactly one of "image" (an image to pull) or "dockerfile" (a Dockerfile to build)'
|
|
1428
|
-
});
|
|
1429
|
-
var SERVICE_FIELDS = [
|
|
1430
|
-
{ name: "description", description: "What the service is, in a sentence" },
|
|
1431
|
-
{ name: "agentId", description: "The agent that runs it, from list_agents. Omit to inherit from the environment.", clearable: true },
|
|
1432
|
-
{ name: "cwd", description: `Working directory, RELATIVE to the project root (e.g. "apps/web", or omit for the root). The project is synced between machines and lives in a different folder on each: Runeya resolves a relative cwd against each machine's own project folder, while an absolute path (/home/you/\u2026) breaks on every other machine. Use an absolute path only for something outside the project, written with ~ or an environment variable ($NAME) rather than a literal home directory.`, clearable: true },
|
|
1433
|
-
{ name: "command", description: 'Shortcut for a single command line (e.g. "npm run dev"). Replaces every existing command. Use commands for several.' },
|
|
1434
|
-
{ name: "commands", description: 'The processes of the service. They all start AT THE SAME TIME, in parallel, and the service runs while they run \u2014 not one after another. Use several for processes that live side by side (a web server and a worker). Steps that must follow each other (build, then install, then launch) go in ONE command chained with &&. A one-off action the user triggers by hand (build, deploy, read logs) is a shortcut, not a command. Each command runs in the service cwd, or its own "cwd", relative to the project root. No absolute paths of this machine: the service is synced to other machines. Replaces every existing command. "id" is generated when omitted; "shell" runs the line through a shell (default true).', schema: z3.array(optionalId(ServiceCommandSchema)).max(50) },
|
|
1435
|
-
{ name: "ports", description: "Ports the service listens on. Declare them: they become {{service.PORT}}, {{service.URL}} and {{services.<slug>.URL}} for the other services, which environment variables should reference instead of repeating the numbers.", schema: ServiceConfigSchema.shape.ports.unwrap().unwrap() },
|
|
1436
|
-
{ name: "groups", description: "Groups the service belongs to. Replaces the current ones.", schema: ServiceConfigSchema.shape.groups.unwrap().unwrap() },
|
|
1437
|
-
{ name: "url", description: "URL where the service is reached" },
|
|
1438
|
-
{ name: "localUrls", description: 'Local domain names routed to a port of the service (e.g. {"url":"api.localhost.dev","port":3000})', schema: ServiceConfigSchema.shape.localUrls.unwrap().unwrap() },
|
|
1439
|
-
{ name: "openapiUrl", description: "URL of its OpenAPI document" },
|
|
1440
|
-
{ name: "docsPath", description: "Where its markdown docs live, relative to cwd or absolute. Defaults to cwd." },
|
|
1441
|
-
{ name: "git", description: 'Its git repository: "remote" URL and "home" page', schema: ServiceConfigSchema.shape.git.unwrap(), clearable: true },
|
|
1442
|
-
{ name: "meta", description: "Free key/value metadata (strings)", schema: ServiceConfigSchema.shape.meta.unwrap(), clearable: true },
|
|
1443
|
-
{ name: "runner", description: '"native" runs the commands on the machine; "docker" runs the service in a container and then needs dockerConfig', schema: ServiceConfigSchema.shape.runner.unwrap().unwrap() },
|
|
1444
|
-
{ name: "dockerConfig", description: 'With runner "docker": the container. Exactly one of "image" (pull) or "dockerfile" (inline Dockerfile, built with "buildContext", "buildArgs", "targetStage"). Ports and volumes use Docker syntax ("8080:80", "./data:/data"); host paths in volumes relative to the service directory, never an absolute path of this machine. "useNativeCommand" runs the service commands inside the container instead of its CMD ("nativeCommandMode": one shared container or one per command). "bootstrapCommands" run once when the container starts. Replaces the whole Docker configuration: read it first with get_service to keep what you do not change.', schema: DockerConfigInput },
|
|
1445
|
-
{ name: "healthCheck", description: 'How to tell the service is ready: an HTTP "path" to call, or a "command" that must succeed', schema: HealthCheckSchema, clearable: true },
|
|
1446
|
-
{ name: "autoRestart", description: "Restart the service when it crashes", schema: z3.boolean() },
|
|
1447
|
-
{ name: "restartStrategy", description: "When to restart it", schema: RestartStrategySchema.unwrap() },
|
|
1448
|
-
{ name: "maxRestarts", description: "Give up after this many restarts", schema: ServiceConfigSchema.shape.maxRestarts.unwrap() },
|
|
1449
|
-
{ name: "restartBackoffMs", description: "Delay before a restart, in milliseconds", schema: ServiceConfigSchema.shape.restartBackoffMs.unwrap().unwrap() },
|
|
1450
|
-
{ name: "clearLogsOnStart", description: "Clear the logs each time the service starts", schema: z3.boolean() },
|
|
1451
|
-
{ name: "shortcuts", description: 'One-click actions shown on the service, run on demand and independently of the running commands (build, deploy, migrate, read logs). Same path rules as commands: relative to the project root, never an absolute path of this machine. Replaces the current ones. "id" is generated when omitted.', schema: z3.array(optionalId(ServiceShortcutSchema)).max(50) },
|
|
1452
|
-
{ name: "parserIds", description: "Log parsers applied to its output, by id", schema: ServiceConfigSchema.shape.parserIds.unwrap() },
|
|
1453
|
-
{ name: "logSources", description: 'Extra log sources beyond the console output (files, databases\u2026). Replaces the current ones. Credentials (mongo connectionString, mysql password) read as "***": send "***" back to keep the stored value, or the real value to change it.', schema: ServiceConfigSchema.shape.logSources.unwrap().unwrap() }
|
|
1454
|
-
];
|
|
1455
|
-
function serviceParams(clearable2) {
|
|
1456
|
-
return SERVICE_FIELDS.map((f) => {
|
|
1457
|
-
const nullable = clearable2 && f.clearable;
|
|
1458
|
-
const base = f.schema ?? (nullable ? z3.string() : void 0);
|
|
1459
|
-
return {
|
|
1460
|
-
name: f.name,
|
|
1461
|
-
description: nullable ? `${f.description} null clears it.` : f.description,
|
|
1462
|
-
required: false,
|
|
1463
|
-
...base ? { schema: nullable ? base.nullable() : base } : {}
|
|
1464
|
-
};
|
|
1465
|
-
});
|
|
1466
|
-
}
|
|
1467
|
-
function serviceFields(p, params) {
|
|
1468
|
-
const out = {};
|
|
1469
|
-
for (const param of params) {
|
|
1470
|
-
if (p[param.name] === void 0 || param.name === "command") continue;
|
|
1471
|
-
out[param.name] = param.schema ? parseTyped(param.name, param.schema, p[param.name]) : p[param.name];
|
|
1472
|
-
}
|
|
1473
|
-
if (p.command !== void 0 && p.commands === void 0) out["commands"] = [{ label: "", command: p.command, shell: true }];
|
|
1474
|
-
if (Array.isArray(out["commands"])) out["commands"] = withIds(out["commands"]);
|
|
1475
|
-
if (Array.isArray(out["shortcuts"])) out["shortcuts"] = withIds(out["shortcuts"]);
|
|
1476
|
-
const docker = out["dockerConfig"];
|
|
1477
|
-
if (docker?.bootstrapCommands) out["dockerConfig"] = { ...docker, bootstrapCommands: withIds(docker.bootstrapCommands) };
|
|
1478
|
-
return out;
|
|
1479
|
-
}
|
|
1480
|
-
function maskServices(result) {
|
|
1481
|
-
if (Array.isArray(result)) return result.map(maskServices);
|
|
1482
|
-
if (result && typeof result === "object" && Array.isArray(result.logSources)) {
|
|
1483
|
-
const service = result;
|
|
1484
|
-
return { ...service, logSources: maskLogSourceSecrets(service.logSources) };
|
|
1485
|
-
}
|
|
1486
|
-
return result;
|
|
1487
|
-
}
|
|
1488
|
-
var refs = (scope) => BUILTIN_VARIABLES.filter((b) => b.scope === scope).map((b) => `{{${b.name}}}`).join(", ");
|
|
1489
|
-
var BUILTINS_HELP = `Built-in references Runeya fills itself \u2014 filled when the service is deployed, from the service that receives the variable: ${refs("server")}, the numbered {{service.PORT_2}} / {{service.URL_2}}\u2026 for its other ports, and {{services.<slug>.PORT}}, .URL, .BASE_URL, .NAME, .ID for a sibling service of the project (slug = its name in lowercase-dashes). Filled on the machine when the service starts: ${refs("agent")}.`;
|
|
1490
|
-
var CREATE_SERVICE_PARAMS = serviceParams(false);
|
|
1491
|
-
var UPDATE_SERVICE_PARAMS = serviceParams(true);
|
|
1492
|
-
var RUNEYA_CAPABILITIES = [
|
|
1493
|
-
{
|
|
1494
|
-
name: "list_services",
|
|
1495
|
-
transformOutput: maskServices,
|
|
1496
|
-
description: "List services, with the serviceId and agentId to use in other calls. Pass the projectId your context names to stay on the project the user is looking at, or another one from list_projects to look elsewhere. Called with no project, this can answer for every project of every organization on the machine \u2014 far more than the interface shows.",
|
|
1497
|
-
route: "service.list",
|
|
1498
|
-
method: "GET",
|
|
1499
|
-
params: [
|
|
1500
|
-
{ name: "projectId", description: "Restrict to this project, from list_projects. Omit to list every service on the machine.", required: false },
|
|
1501
|
-
{ name: "orgId", description: "Its organization. Needed only when the same project id exists in several.", required: false }
|
|
1502
|
-
],
|
|
1503
|
-
buildInput: (p) => p.projectId ? { projectId: p.projectId, ...p.orgId ? { orgId: p.orgId } : {} } : void 0
|
|
1504
|
-
},
|
|
1505
|
-
{
|
|
1506
|
-
name: "get_service_status",
|
|
1507
|
-
description: "Get the current status (running, stopped, etc.) of a service. A service that has never been started on this agent has no process yet, and this answers 404 Process not found \u2014 that means STOPPED, not forbidden and not missing. Start it, or read its configuration with get_service.",
|
|
1508
|
-
route: "process.get",
|
|
1509
|
-
method: "GET",
|
|
1510
|
-
params: [
|
|
1511
|
-
{ name: "serviceId", description: "The service ID", required: true },
|
|
1512
|
-
{ name: "agentId", description: "The agent ID hosting this service", required: true }
|
|
1513
|
-
],
|
|
1514
|
-
buildInput: (p) => ({ agentId: p.agentId, id: p.serviceId })
|
|
1515
|
-
},
|
|
1516
|
-
{
|
|
1517
|
-
name: "get_logs",
|
|
1518
|
-
description: "Get the recent buffered logs for a service.",
|
|
1519
|
-
route: "process.logs",
|
|
1520
|
-
method: "GET",
|
|
1521
|
-
params: [
|
|
1522
|
-
{ name: "serviceId", description: "The service ID", required: true },
|
|
1523
|
-
{ name: "agentId", description: "The agent ID hosting this service", required: true }
|
|
1524
|
-
],
|
|
1525
|
-
buildInput: (p) => ({ agentId: p.agentId, processId: p.serviceId })
|
|
1526
|
-
},
|
|
1527
|
-
{
|
|
1528
|
-
name: "start_service",
|
|
1529
|
-
description: "Start a service on an agent.",
|
|
1530
|
-
route: "process.start",
|
|
1531
|
-
method: "POST",
|
|
1532
|
-
params: [
|
|
1533
|
-
{ name: "serviceId", description: "The service ID to start", required: true },
|
|
1534
|
-
{ name: "agentId", description: "The agent ID hosting this service", required: true }
|
|
1535
|
-
],
|
|
1536
|
-
buildInput: (p) => ({ agentId: p.agentId, processId: p.serviceId }),
|
|
1537
|
-
destructive: true
|
|
1538
|
-
},
|
|
1539
|
-
{
|
|
1540
|
-
name: "stop_service",
|
|
1541
|
-
description: "Stop a running service on an agent.",
|
|
1542
|
-
route: "process.stop",
|
|
1543
|
-
method: "POST",
|
|
1544
|
-
params: [
|
|
1545
|
-
{ name: "serviceId", description: "The service ID to stop", required: true },
|
|
1546
|
-
{ name: "agentId", description: "The agent ID hosting this service", required: true }
|
|
1547
|
-
],
|
|
1548
|
-
buildInput: (p) => ({ agentId: p.agentId, processId: p.serviceId }),
|
|
1549
|
-
destructive: true
|
|
1550
|
-
},
|
|
1551
|
-
{
|
|
1552
|
-
name: "restart_service",
|
|
1553
|
-
description: "Restart a service on an agent (stop \u2192 redeploy \u2192 start).",
|
|
1554
|
-
route: "process.restart",
|
|
1555
|
-
method: "POST",
|
|
1556
|
-
params: [
|
|
1557
|
-
{ name: "serviceId", description: "The service ID to restart", required: true },
|
|
1558
|
-
{ name: "agentId", description: "The agent ID hosting this service", required: true }
|
|
1559
|
-
],
|
|
1560
|
-
buildInput: (p) => ({ agentId: p.agentId, processId: p.serviceId }),
|
|
1561
|
-
destructive: true
|
|
1562
|
-
},
|
|
1563
|
-
// ─── Utility ─────────────────────────────────────────────────────────────
|
|
1564
|
-
{
|
|
1565
|
-
name: "wait",
|
|
1566
|
-
description: "Wait for a given number of milliseconds before continuing.",
|
|
1567
|
-
route: "utility.wait",
|
|
1568
|
-
method: "POST",
|
|
1569
|
-
params: [
|
|
1570
|
-
{ name: "ms", description: "Number of MILLISECONDS to wait. Convert from seconds: 1s=1000, 10s=10000, 1min=60000. Max 300000.", required: true }
|
|
1571
|
-
],
|
|
1572
|
-
buildInput: (p) => ({ ms: Number(p.ms) }),
|
|
1573
|
-
usageHint: '"wait 5s" \u2192 wait(ms=5000), "pause 10 seconds" \u2192 wait(ms=10000), "attends 3 secondes" \u2192 wait(ms=3000). Always convert to milliseconds.'
|
|
1574
|
-
},
|
|
1575
|
-
// ─── Kanban ───────────────────────────────────────────────────────────────
|
|
1576
|
-
{
|
|
1577
|
-
name: "kanban_list_boards",
|
|
1578
|
-
description: "List the kanban boards of the organization. Returns the organizationId actually queried, the boardId to use in the other kanban tools, plus column and card counts. Cards themselves are not included \u2014 use kanban_get_board for those. An empty list means that organization really has no board: a failure to reach the cloud is reported as an error instead, never as an empty list.",
|
|
1579
|
-
route: "kanban.listBoards",
|
|
1580
|
-
method: "GET",
|
|
1581
|
-
params: [
|
|
1582
|
-
{ name: "includeArchived", description: 'Set to "true" to include archived boards. Default: false.', required: false },
|
|
1583
|
-
{ name: "organizationId", description: "Which organization to read. Optional: needed only when the account belongs to several and the error message asks for it.", required: false }
|
|
1584
|
-
],
|
|
1585
|
-
buildInput: (p) => ({
|
|
1586
|
-
includeArchived: p.includeArchived === "true",
|
|
1587
|
-
...p.organizationId ? { organizationId: p.organizationId } : {}
|
|
1588
|
-
})
|
|
1589
|
-
},
|
|
1590
|
-
{
|
|
1591
|
-
name: "kanban_get_board",
|
|
1592
|
-
description: "Read one kanban board: its columns, and the cards in each (id, title, markdown body, assignees, comment count, and attachment metadata \u2014 use kanban_download_attachment to fetch the bytes of a file). Use the exact column names it returns when moving or adding a card.",
|
|
1593
|
-
route: "kanban.getBoard",
|
|
1594
|
-
method: "GET",
|
|
1595
|
-
params: [
|
|
1596
|
-
{ name: "boardId", description: "The kanban board ID, from kanban_list_boards", required: true }
|
|
1597
|
-
],
|
|
1598
|
-
buildInput: (p) => ({ boardId: p.boardId })
|
|
1599
|
-
},
|
|
1600
|
-
{
|
|
1601
|
-
name: "kanban_get_card_comments",
|
|
1602
|
-
description: "Read the comment thread of one kanban card, newest last: who wrote each comment (ai or user, with the person's name), when, its text, and its attachments. The comments in your task context are a snapshot taken when the task started \u2014 call this to see anything written since, whenever someone tells you a comment was added or kanban_get_board reports a higher commentCount than you have.",
|
|
1603
|
-
route: "kanban.getCardComments",
|
|
1604
|
-
method: "GET",
|
|
1605
|
-
params: [
|
|
1606
|
-
{ name: "boardId", description: "The kanban board ID", required: true },
|
|
1607
|
-
{ name: "cardId", description: "The card ID whose comments to read", required: true },
|
|
1608
|
-
{ name: "limit", description: "How many of the most recent comments to return (1-200). Default: 50.", required: false }
|
|
1609
|
-
],
|
|
1610
|
-
buildInput: (p) => ({
|
|
1611
|
-
boardId: p.boardId,
|
|
1612
|
-
cardId: p.cardId,
|
|
1613
|
-
...p.limit ? { limit: Number(p.limit) } : {}
|
|
1614
|
-
}),
|
|
1615
|
-
usageHint: '"le support a ajout\xE9 un commentaire" / "regarde les nouveaux commentaires" \u2192 kanban_get_card_comments(boardId, cardId). Never answer from the snapshot in your context when fresh comments are mentioned.'
|
|
1616
|
-
},
|
|
1617
|
-
{
|
|
1618
|
-
name: "kanban_search_cards",
|
|
1619
|
-
description: 'Search kanban cards by free text, matched against their title, body, comments and the support conversations they follow (title, messages, internal notes, and the names of message authors) \u2014 accent- and case-insensitive. Archived cards are included. Searches every board of the organization unless boardId narrows it down. createdBy narrows to the cards someone created ("les cartes cr\xE9\xE9es par Isabelle"), alone or with a query.',
|
|
1620
|
-
route: "kanban.searchCards",
|
|
1621
|
-
method: "GET",
|
|
1622
|
-
params: [
|
|
1623
|
-
{ name: "query", description: "Text to look for in card titles, bodies, comments and followed conversations. Optional when createdBy is given.", required: false },
|
|
1624
|
-
{ name: "createdBy", description: "Only cards created by this author: a user id, or a name (accent- and case-insensitive, partial match).", required: false },
|
|
1625
|
-
{ name: "boardId", description: "Restrict the search to this board. Omit to search all boards.", required: false },
|
|
1626
|
-
{ name: "limit", description: "Maximum number of cards to return (1-100). Default: 25.", required: false },
|
|
1627
|
-
{ name: "organizationId", description: "Which organization to search. Optional: needed only when the account belongs to several and the error message asks for it.", required: false }
|
|
1628
|
-
],
|
|
1629
|
-
buildInput: (p) => ({
|
|
1630
|
-
...p.query ? { query: p.query } : {},
|
|
1631
|
-
...p.createdBy ? { createdBy: p.createdBy } : {},
|
|
1632
|
-
...p.boardId ? { boardId: p.boardId } : {},
|
|
1633
|
-
...p.limit ? { limit: Number(p.limit) } : {},
|
|
1634
|
-
...p.organizationId ? { organizationId: p.organizationId } : {}
|
|
1635
|
-
})
|
|
1636
|
-
},
|
|
1637
|
-
{
|
|
1638
|
-
name: "kanban_download_attachment",
|
|
1639
|
-
description: "Download a kanban card attachment (image, PDF, any file) onto this machine and return its local path, so it can be opened with file-reading tools. Attachment ids come from the card context, from kanban_get_board, or from kanban_get_card_comments \u2014 a file attached to a comment downloads exactly like one attached to the card.",
|
|
1640
|
-
route: "kanban.downloadAttachment",
|
|
1641
|
-
method: "POST",
|
|
1642
|
-
params: [
|
|
1643
|
-
{ name: "attachmentId", description: "The attachment ID, as listed on the card", required: true },
|
|
1644
|
-
{ name: "boardId", description: "The board the attachment comes from. Pass it whenever you know it: on a machine linked to several cloud accounts, it is what says which one holds the file.", required: false },
|
|
1645
|
-
{ name: "organizationId", description: "Which organization the attachment belongs to. Optional: needed only when neither the board id is known nor the machine has a single account.", required: false }
|
|
1646
|
-
],
|
|
1647
|
-
buildInput: (p) => ({
|
|
1648
|
-
attachmentId: p.attachmentId,
|
|
1649
|
-
...p.boardId ? { boardId: p.boardId } : {},
|
|
1650
|
-
...p.organizationId ? { orgId: p.organizationId } : {}
|
|
1651
|
-
})
|
|
1652
|
-
},
|
|
1653
|
-
{
|
|
1654
|
-
name: "kanban_move_card",
|
|
1655
|
-
description: "Move a kanban card to another column. Use the exact column name.",
|
|
1656
|
-
route: "kanban.moveCard",
|
|
1657
|
-
method: "POST",
|
|
1658
|
-
params: [
|
|
1659
|
-
{ name: "boardId", description: "The kanban board ID", required: true },
|
|
1660
|
-
{ name: "cardId", description: "The card ID to move", required: true },
|
|
1661
|
-
{ name: "targetColumn", description: "Exact name of the target column", required: true }
|
|
1662
|
-
],
|
|
1663
|
-
buildInput: (p) => ({ boardId: p.boardId, cardId: p.cardId, targetColumn: p.targetColumn })
|
|
1664
|
-
},
|
|
1665
|
-
{
|
|
1666
|
-
name: "kanban_add_comment",
|
|
1667
|
-
description: "Add a comment to a kanban card.",
|
|
1668
|
-
route: "kanban.addComment",
|
|
1669
|
-
method: "POST",
|
|
1670
|
-
params: [
|
|
1671
|
-
{ name: "boardId", description: "The kanban board ID", required: true },
|
|
1672
|
-
{ name: "cardId", description: "The card ID", required: true },
|
|
1673
|
-
{ name: "comment", description: "The comment text (markdown supported)", required: true }
|
|
1674
|
-
],
|
|
1675
|
-
buildInput: (p) => ({ boardId: p.boardId, cardId: p.cardId, comment: p.comment })
|
|
1676
|
-
},
|
|
1677
|
-
{
|
|
1678
|
-
name: "kanban_get_card_conversations",
|
|
1679
|
-
description: "Read the customer support conversations (Intercom\u2026) linked to one kanban card: for each, its title, provider, state (open/resolved), link, the opening message and the thread of messages (author name, customer or team, internal note or not, date, text, attached files \u2014 fetch their bytes with kanban_download_attachment), plus the other cards following the same conversation. These messages are NOT comments of the card \u2014 read them here.",
|
|
1680
|
-
route: "kanban.getCardConversations",
|
|
1681
|
-
method: "GET",
|
|
1682
|
-
params: [
|
|
1683
|
-
{ name: "boardId", description: "The kanban board ID", required: true },
|
|
1684
|
-
{ name: "cardId", description: "The card ID whose conversations to read", required: true },
|
|
1685
|
-
{ name: "limit", description: "How many of the most recent messages to return per conversation (1-500). Default: 100.", required: false }
|
|
1686
|
-
],
|
|
1687
|
-
buildInput: (p) => ({
|
|
1688
|
-
boardId: p.boardId,
|
|
1689
|
-
cardId: p.cardId,
|
|
1690
|
-
...p.limit ? { limit: Number(p.limit) } : {}
|
|
1691
|
-
}),
|
|
1692
|
-
usageHint: `"regarde la conversation Intercom de la carte" / "qu'a dit le client" \u2192 kanban_get_card_conversations(boardId, cardId).`
|
|
1693
|
-
},
|
|
1694
|
-
{
|
|
1695
|
-
name: "kanban_search_conversations",
|
|
1696
|
-
description: "Search customer support conversations (Intercom\u2026) at the providers connected to the board's organization, by words of the conversation title, or by conversation number or URL. Read-only at the provider. Each result gives connectionId and externalId (needed to link it), title, state, a preview and the cards already following it.",
|
|
1697
|
-
route: "kanban.searchConversations",
|
|
1698
|
-
method: "GET",
|
|
1699
|
-
params: [
|
|
1700
|
-
{ name: "boardId", description: "Any kanban board ID of the organization to search in", required: true },
|
|
1701
|
-
{ name: "query", description: "Words of the conversation title, a conversation number, or a conversation URL", required: true }
|
|
1702
|
-
],
|
|
1703
|
-
buildInput: (p) => ({ boardId: p.boardId, query: p.query })
|
|
1704
|
-
},
|
|
1705
|
-
{
|
|
1706
|
-
name: "kanban_link_conversation",
|
|
1707
|
-
description: "Link a customer support conversation found with kanban_search_conversations to a kanban card. Its whole thread is imported and new messages keep arriving on the card. A conversation can be linked to several cards. Nothing is written at the provider.",
|
|
1708
|
-
route: "kanban.linkConversation",
|
|
1709
|
-
method: "POST",
|
|
1710
|
-
params: [
|
|
1711
|
-
{ name: "boardId", description: "The kanban board ID of the card", required: true },
|
|
1712
|
-
{ name: "cardId", description: "The card to link the conversation to", required: true },
|
|
1713
|
-
{ name: "connectionId", description: "The connectionId of the search result", required: true },
|
|
1714
|
-
{ name: "externalId", description: "The externalId of the search result", required: true }
|
|
1715
|
-
],
|
|
1716
|
-
buildInput: (p) => ({ boardId: p.boardId, cardId: p.cardId, connectionId: p.connectionId, externalId: p.externalId })
|
|
1717
|
-
},
|
|
1718
|
-
{
|
|
1719
|
-
name: "kanban_get_card_links",
|
|
1720
|
-
description: "Read the filiation of a board: which card depends on which. Returns one entry per link (child card \u2194 parent card), plus the title, board, column, assignees and comment count of any linked card living on another board. Use it when a card context says it has a parent or sub-cards and you need their ids to read them.",
|
|
1721
|
-
route: "kanban.getCardLinks",
|
|
1722
|
-
method: "GET",
|
|
1723
|
-
params: [
|
|
1724
|
-
{ name: "boardId", description: "The kanban board ID whose links to read", required: true }
|
|
1725
|
-
],
|
|
1726
|
-
buildInput: (p) => ({ boardId: p.boardId })
|
|
1727
|
-
},
|
|
1728
|
-
{
|
|
1729
|
-
name: "kanban_set_card_parent",
|
|
1730
|
-
description: "Link a kanban card to a parent card, or detach it. The parent is the card the other one depends on \u2014 an epic and its tasks, a bug and its follow-ups. A card has at most one parent, and setting a new one replaces it. Omit parentCardId to detach. kanban_get_board reports the current filiation as parentCardId / childCardIds on each card.",
|
|
1731
|
-
route: "kanban.setCardParent",
|
|
1732
|
-
method: "POST",
|
|
1733
|
-
params: [
|
|
1734
|
-
{ name: "boardId", description: "The kanban board ID of the card being linked", required: true },
|
|
1735
|
-
{ name: "cardId", description: "The card that depends on the parent (the child)", required: true },
|
|
1736
|
-
{ name: "parentCardId", description: "The parent card ID. Omit to detach the card from its parent.", required: false },
|
|
1737
|
-
{ name: "parentBoardId", description: "The parent's board, when it lives on another board of the same organization. Defaults to boardId.", required: false }
|
|
1738
|
-
],
|
|
1739
|
-
buildInput: (p) => ({
|
|
1740
|
-
boardId: p.boardId,
|
|
1741
|
-
cardId: p.cardId,
|
|
1742
|
-
...p.parentCardId ? { parentCardId: p.parentCardId } : {},
|
|
1743
|
-
...p.parentBoardId ? { parentBoardId: p.parentBoardId } : {}
|
|
1744
|
-
})
|
|
1745
|
-
},
|
|
1746
|
-
{
|
|
1747
|
-
name: "kanban_place_card",
|
|
1748
|
-
description: "Place an existing kanban card on another board of the same organization, without copying it \u2014 a reference. The card stays on its origin board; the target board gives it a column of its own. Editing, commenting, archiving or deleting the card from either board acts on the same card; moving it on the target board only moves the reference. Use it to show an issue from an issue list on a team kanban, for instance.",
|
|
1749
|
-
route: "kanban.placeCard",
|
|
1750
|
-
method: "POST",
|
|
1751
|
-
params: [
|
|
1752
|
-
{ name: "boardId", description: "The board to place the card on (not its own board)", required: true },
|
|
1753
|
-
{ name: "cardId", description: "The card to place", required: true },
|
|
1754
|
-
{ name: "column", description: "The column on that board: its ID or its title", required: true }
|
|
1755
|
-
],
|
|
1756
|
-
buildInput: (p) => ({ boardId: p.boardId, cardId: p.cardId, column: p.column })
|
|
1757
|
-
},
|
|
1758
|
-
{
|
|
1759
|
-
name: "kanban_remove_card_placement",
|
|
1760
|
-
description: "Remove a card from a board where it was placed as a reference. The card itself is untouched and stays on its origin board.",
|
|
1761
|
-
route: "kanban.unplaceCard",
|
|
1762
|
-
method: "POST",
|
|
1763
|
-
params: [
|
|
1764
|
-
{ name: "boardId", description: "The board the reference is on", required: true },
|
|
1765
|
-
{ name: "cardId", description: "The card to remove from that board", required: true }
|
|
1766
|
-
],
|
|
1767
|
-
buildInput: (p) => ({ boardId: p.boardId, cardId: p.cardId })
|
|
1768
|
-
},
|
|
1769
|
-
{
|
|
1770
|
-
name: "kanban_get_card_placements",
|
|
1771
|
-
description: "List where a kanban card is: its origin board (home: true), then every board it is placed on as a reference, with the column on each. kanban_get_board flags a referenced card with an `origin` field naming its origin board.",
|
|
1772
|
-
route: "kanban.getCardPlacements",
|
|
1773
|
-
method: "GET",
|
|
1774
|
-
params: [
|
|
1775
|
-
{ name: "boardId", description: "Any board the card is on", required: true },
|
|
1776
|
-
{ name: "cardId", description: "The card", required: true }
|
|
1777
|
-
],
|
|
1778
|
-
buildInput: (p) => ({ boardId: p.boardId, cardId: p.cardId })
|
|
1779
|
-
},
|
|
1780
|
-
{
|
|
1781
|
-
name: "kanban_add_card",
|
|
1782
|
-
description: "Add a new card to a kanban column.",
|
|
1783
|
-
route: "kanban.addCard",
|
|
1784
|
-
method: "POST",
|
|
1785
|
-
params: [
|
|
1786
|
-
{ name: "boardId", description: "The kanban board ID", required: true },
|
|
1787
|
-
{ name: "column", description: "Exact name of the target column", required: true },
|
|
1788
|
-
{ name: "title", description: "Card title", required: true },
|
|
1789
|
-
{ name: "content", description: "Card content in markdown", required: false }
|
|
1790
|
-
],
|
|
1791
|
-
buildInput: (p) => ({ boardId: p.boardId, column: p.column, title: p.title, content: p.content })
|
|
1792
|
-
},
|
|
1793
|
-
{
|
|
1794
|
-
name: "kanban_get_card",
|
|
1795
|
-
description: "Read one kanban card by id, including archived ones. Cheaper than fetching the whole board, and the only way to read a card that has been archived.",
|
|
1796
|
-
route: "kanban.getCard",
|
|
1797
|
-
method: "GET",
|
|
1798
|
-
params: [
|
|
1799
|
-
{ name: "boardId", description: "The kanban board ID", required: true },
|
|
1800
|
-
{ name: "cardId", description: "The card ID", required: true }
|
|
1801
|
-
],
|
|
1802
|
-
buildInput: (p) => ({ boardId: p.boardId, cardId: p.cardId })
|
|
1803
|
-
},
|
|
1804
|
-
{
|
|
1805
|
-
name: "kanban_update_card",
|
|
1806
|
-
description: "Update an existing kanban card. Only the fields you pass are changed; passing null to priority, color or deadline clears it. Prefer this over creating a second card when something needs correcting.",
|
|
1807
|
-
route: "kanban.updateCard",
|
|
1808
|
-
method: "POST",
|
|
1809
|
-
params: [
|
|
1810
|
-
{ name: "boardId", description: "The kanban board ID", required: true },
|
|
1811
|
-
{ name: "cardId", description: "The card ID", required: true },
|
|
1812
|
-
{ name: "title", description: "New title", required: false },
|
|
1813
|
-
{ name: "content", description: "New card content, in markdown", required: false },
|
|
1814
|
-
{ name: "priority", description: "Priority from 1 to 10, or null to clear it", required: false },
|
|
1815
|
-
{ name: "color", description: "Card colour, or null to clear it", required: false },
|
|
1816
|
-
{ name: "groups", description: "Labels, as a list of strings. Replaces the current ones.", required: false },
|
|
1817
|
-
{ name: "deadline", description: "Due date as YYYY-MM-DD, or null to clear it", required: false },
|
|
1818
|
-
{ name: "assignees", description: "User ids to assign, as a list. Replaces the current ones; use kanban_list_members to find the ids.", required: false }
|
|
1819
|
-
],
|
|
1820
|
-
buildInput: (p) => ({
|
|
1821
|
-
boardId: p.boardId,
|
|
1822
|
-
cardId: p.cardId,
|
|
1823
|
-
...p.title !== void 0 ? { title: p.title } : {},
|
|
1824
|
-
...p.content !== void 0 ? { content: p.content } : {},
|
|
1825
|
-
// Tout arrive en chaîne : un modèle n'écrit pas des nombres, des listes
|
|
1826
|
-
// ni des `null` typés. `clearable` distingue « efface » de « ne touche
|
|
1827
|
-
// pas » — sans quoi vider une couleur serait impossible à exprimer, et
|
|
1828
|
-
// changer un titre risquerait de vider le reste.
|
|
1829
|
-
...clearable(p.priority, (v) => Number(v), "priority"),
|
|
1830
|
-
...clearable(p.color, (v) => v, "color"),
|
|
1831
|
-
...clearable(p.deadline, (v) => v, "deadline"),
|
|
1832
|
-
...p.groups !== void 0 ? { groups: toList(p.groups) } : {},
|
|
1833
|
-
...p.assignees !== void 0 ? { assignees: toList(p.assignees) } : {}
|
|
1834
|
-
})
|
|
1835
|
-
},
|
|
1836
|
-
{
|
|
1837
|
-
name: "kanban_set_card_archived",
|
|
1838
|
-
description: "Archive a kanban card (it leaves the board but is not deleted) or bring it back. An unarchived card returns to the column it left.",
|
|
1839
|
-
route: "kanban.setCardArchived",
|
|
1840
|
-
method: "POST",
|
|
1841
|
-
params: [
|
|
1842
|
-
{ name: "boardId", description: "The kanban board ID", required: true },
|
|
1843
|
-
{ name: "cardId", description: "The card ID", required: true },
|
|
1844
|
-
{ name: "archived", description: "true to archive, false to bring the card back", required: true }
|
|
1845
|
-
],
|
|
1846
|
-
buildInput: (p) => ({ boardId: p.boardId, cardId: p.cardId, archived: p.archived === "true" })
|
|
1847
|
-
},
|
|
1848
|
-
{
|
|
1849
|
-
name: "kanban_list_members",
|
|
1850
|
-
description: "List the people of the organization who can be assigned to a card, with their ids. Needed before assigning anyone with kanban_update_card.",
|
|
1851
|
-
route: "kanban.listMembers",
|
|
1852
|
-
method: "GET",
|
|
1853
|
-
params: [
|
|
1854
|
-
{ name: "organizationId", description: "Which organization. Optional: needed only when the account belongs to several and the error message asks for it.", required: false }
|
|
1855
|
-
],
|
|
1856
|
-
buildInput: (p) => p.organizationId ? { organizationId: p.organizationId } : {}
|
|
1857
|
-
},
|
|
1858
|
-
// ─── Lecture seule ───────────────────────────────────────────────────────
|
|
1859
|
-
//
|
|
1860
|
-
// Tout ce qui se consulte sans rien changer. Les écritures s'ajoutent au cas
|
|
1861
|
-
// par cas : aujourd'hui les services et leurs variables, plus bas.
|
|
1862
|
-
//
|
|
1863
|
-
// Volontairement absentes, et à ne pas ajouter sans y regarder à deux fois,
|
|
1864
|
-
// parce qu'elles rendent un secret : `environment.list` / `get` / `resolve` /
|
|
1865
|
-
// `resolveFlat` (un `Environment` porte ses variables, valeurs comprises),
|
|
1866
|
-
// `apiKeys.list` / `reveal`, `setup.getEncryptionKeyHex` et `getOrgKeys`
|
|
1867
|
-
// (clés de chiffrement), `settings.get` et `settings.listAIProviders` (clés
|
|
1868
|
-
// de fournisseurs d'IA — `settings.getPaths` et `getNetwork`, eux, ne
|
|
1869
|
-
// rendent que des chemins et une adresse, d'où leur présence ci-dessous),
|
|
1870
|
-
// `cloudAuth.session`, `agent.getPassthroughEnv`. Un agent n'a pas besoin de
|
|
1871
|
-
// ces valeurs pour travailler, et ce qu'il lit finit dans une transcription.
|
|
1872
|
-
//
|
|
1873
|
-
// La seule exception est `service.getEnv` (`get_service_env` ci-dessous),
|
|
1874
|
-
// et elle n'en est une que parce qu'elle filtre : les variables publiques, et
|
|
1875
|
-
// les seuls secrets que leur auteur a partagés avec les IA (`isSharedWithAi`
|
|
1876
|
-
// — « Lisible par l'IA », ou l'injection, qui vaut la lecture). Un secret non
|
|
1877
|
-
// partagé n'y apparaît pas, pas même par son nom.
|
|
1878
|
-
{
|
|
1879
|
-
name: "list_processes",
|
|
1880
|
-
description: "List every process across all agents with its current state (running, stopped, exit code, uptime). Use this to see the whole machine at once, rather than calling get_service_status service by service. An agent only learns about a service when it is first started, so this lists what is deployed, not what is configured: an empty list means nothing has been started, not that you cannot see them \u2014 list_services shows what exists.",
|
|
1881
|
-
route: "process.list",
|
|
1882
|
-
method: "GET",
|
|
1883
|
-
params: [],
|
|
1884
|
-
buildInput: () => void 0
|
|
1885
|
-
},
|
|
1886
|
-
{
|
|
1887
|
-
name: "get_service",
|
|
1888
|
-
transformOutput: maskServices,
|
|
1889
|
-
description: "Read the full configuration of one service: its commands, ports, groups, runner, log sources and restart policy. list_services gives the ids.",
|
|
1890
|
-
route: "service.get",
|
|
1891
|
-
method: "GET",
|
|
1892
|
-
params: [
|
|
1893
|
-
{ name: "serviceId", description: "The service ID", required: true }
|
|
1894
|
-
],
|
|
1895
|
-
buildInput: (p) => ({ id: p.serviceId })
|
|
1896
|
-
},
|
|
1897
|
-
{
|
|
1898
|
-
name: "get_service_env",
|
|
1899
|
-
description: 'Read the environment variables a service runs with, and the project\'s variable inventory. `env` lists every key the service receives; a value reads "***" when it is a secret whose author did not share it with AI (sharing = ticking "AI read", or injecting it into the agents\' environment, which grants reading too). `envSecrets` says which keys are secret, `hiddenKeys` which ones are masked. A masked key is set on the service: never treat it as missing, never suggest adding it, and never pass "***" as a value \u2014 ask the user for it. `variables` describes every variable of the project \u2014 which environment defines it and its scope, its description, its flags, whether this machine overrides it, and `inService: false` for the ones this service does not receive. Use it to say where a variable must be changed instead of guessing. On an overridden variable, `sharedValue` is what the machine-local override replaces (the team\'s value, masked as "***" when unreadable); no other value appears there. This is the resolver: the values are what the service would receive \u2014 inheritance, {{environment.KEY}} references, this machine\'s overrides and server built-ins applied; agent built-ins stay as written until the service starts. Use it to check a variable you just composed. `unresolvedReferences` lists references nothing will fill (a typo, a variable that does not exist): fix them.',
|
|
1900
|
-
route: "service.getEnv",
|
|
1901
|
-
method: "GET",
|
|
1902
|
-
params: [
|
|
1903
|
-
{ name: "serviceId", description: "The service ID", required: true },
|
|
1904
|
-
{ name: "environmentId", description: "A global environment of the project to resolve in instead of the active one, without activating it (from list_environments). Omit for the active one.", required: false }
|
|
1905
|
-
],
|
|
1906
|
-
buildInput: (p) => ({ id: p.serviceId, ...p.environmentId ? { environmentId: p.environmentId } : {} })
|
|
1907
|
-
},
|
|
1908
|
-
// ─── Écrire un service et ses variables ────────────────────────────────────
|
|
1909
|
-
//
|
|
1910
|
-
// Les variables s'écrivent à l'aveugle (`environment.setVariableBlind`) : une
|
|
1911
|
-
// IA remplace la valeur d'un secret sans la lire, et ne peut ni le rendre
|
|
1912
|
-
// public, ni le partager avec les IA. La règle tient côté serveur, dans la
|
|
1913
|
-
// route ; ces outils ne passent jamais par une route qui renvoie des valeurs
|
|
1914
|
-
// (`upsertVariable`, `removeVariable`, `update` rendent l'environnement entier).
|
|
1915
|
-
{
|
|
1916
|
-
name: "create_service",
|
|
1917
|
-
transformOutput: maskServices,
|
|
1918
|
-
description: "Create a service, native or Docker, in a project: it joins the project and gets its environments in the same call. Pass the projectId your context names. Projects are synced between machines, so write paths relative to the project root and put machine-specific values (a device serial, a local token) in environment variables, referenced as $NAME in commands \u2014 see the cwd, commands and shortcuts parameters. Then set its variables with set_environment_variable.",
|
|
1919
|
-
route: "service.create",
|
|
1920
|
-
method: "POST",
|
|
1921
|
-
params: [
|
|
1922
|
-
{ name: "name", description: "The service name", required: true },
|
|
1923
|
-
{ name: "projectId", description: "The project it joins: the one your context names, or another from list_projects. Without it, the service belongs to no project.", required: false },
|
|
1924
|
-
{ name: "orgId", description: "Its organization. Needed only when the same project id exists in several.", required: false },
|
|
1925
|
-
...CREATE_SERVICE_PARAMS
|
|
1926
|
-
],
|
|
1927
|
-
buildInput: (p) => {
|
|
1928
|
-
const fields = serviceFields(p, CREATE_SERVICE_PARAMS);
|
|
1929
|
-
if (fields["runner"] === "docker" && !fields["dockerConfig"]) {
|
|
1930
|
-
throw new Error('dockerConfig: required with runner "docker" \u2014 give an "image" or a "dockerfile"');
|
|
1931
|
-
}
|
|
1932
|
-
return {
|
|
1933
|
-
name: p.name,
|
|
1934
|
-
...fields,
|
|
1935
|
-
...p.projectId ? { projectId: p.projectId } : {},
|
|
1936
|
-
...p.orgId ? { orgId: p.orgId } : {}
|
|
1937
|
-
};
|
|
1938
|
-
}
|
|
1939
|
-
},
|
|
1940
|
-
{
|
|
1941
|
-
name: "add_service_to_project",
|
|
1942
|
-
description: "Add an existing service to a project, and create its environments \u2014 one for each of the project's environments, where its own variables go. Not needed after create_service, which already does it; calling it again changes nothing.",
|
|
1943
|
-
route: "project.addService",
|
|
1944
|
-
method: "POST",
|
|
1945
|
-
params: [
|
|
1946
|
-
{ name: "projectId", description: "The project ID, from list_projects", required: true },
|
|
1947
|
-
{ name: "serviceId", description: "The service ID", required: true },
|
|
1948
|
-
{ name: "orgId", description: "Its organization. Needed only when the same project id exists in several.", required: false }
|
|
1949
|
-
],
|
|
1950
|
-
buildInput: (p) => ({ projectId: p.projectId, serviceId: p.serviceId, ...p.orgId ? { orgId: p.orgId } : {} })
|
|
1951
|
-
},
|
|
1952
|
-
{
|
|
1953
|
-
name: "update_service",
|
|
1954
|
-
transformOutput: maskServices,
|
|
1955
|
-
description: "Change any part of a service configuration \u2014 commands, ports, health check, restart policy, shortcuts, log sources, whether it runs natively or in Docker (runner, dockerConfig)\u2026 Only the fields you pass change; a list or an object you pass replaces the current one whole. Read the service first with get_service.",
|
|
1956
|
-
route: "service.update",
|
|
1957
|
-
method: "POST",
|
|
1958
|
-
params: [
|
|
1959
|
-
{ name: "serviceId", description: "The service ID", required: true },
|
|
1960
|
-
{ name: "name", description: "New name", required: false },
|
|
1961
|
-
{ name: "orgId", description: "Move the service to this organization vault. Leave unset unless asked.", required: false, schema: z3.string().max(128).nullable() },
|
|
1962
|
-
...UPDATE_SERVICE_PARAMS
|
|
1963
|
-
],
|
|
1964
|
-
buildInput: (p) => ({
|
|
1965
|
-
id: p.serviceId,
|
|
1966
|
-
...p.name ? { name: p.name } : {},
|
|
1967
|
-
...p.orgId !== void 0 ? { orgId: parseTyped("orgId", z3.string().max(128).nullable(), p.orgId) } : {},
|
|
1968
|
-
...serviceFields(p, UPDATE_SERVICE_PARAMS)
|
|
1969
|
-
})
|
|
1970
|
-
},
|
|
1971
|
-
{
|
|
1972
|
-
name: "list_environments",
|
|
1973
|
-
description: "List the environments of a project, with no value: each one's id, name and scope (global = shared by the whole project, service = one service's own variables), which global environment is active, which service a service environment belongs to and which global environment activates it, its parents (it inherits their variables), `isolated` when a service environment does not inherit from its global one, and the variables it defines with their flags. Empty environments are listed too \u2014 a service you just created has one per global environment, where its own variables go. Use it to find the environmentId before set_environment_variable.",
|
|
1974
|
-
route: "environment.listForAi",
|
|
1975
|
-
method: "GET",
|
|
1976
|
-
params: [
|
|
1977
|
-
{ name: "projectId", description: "The project ID: the one your context names, or another from list_projects", required: true },
|
|
1978
|
-
{ name: "orgId", description: "Its organization. Needed only when the same project id exists in several.", required: false }
|
|
1979
|
-
],
|
|
1980
|
-
buildInput: (p) => ({ projectId: p.projectId, ...p.orgId ? { orgId: p.orgId } : {} })
|
|
1981
|
-
},
|
|
1982
|
-
{
|
|
1983
|
-
name: "resolve_environment",
|
|
1984
|
-
description: "Resolve one environment alone \u2014 its variables with those inherited from its parents and this machine's overrides \u2014 as an AI may read it: secrets not shared with AI read \"***\". Built-in references ({{service.*}}, {{services.*}}, {{agent.*}}\u2026) are NOT filled, since they depend on the service that receives the variable; use get_service_env for a service's final values. `unresolvedReferences` lists references nothing will fill: a misspelled {{environment.KEY}}, or a name that is no built-in.",
|
|
1985
|
-
route: "environment.resolveForAi",
|
|
1986
|
-
method: "GET",
|
|
1987
|
-
params: [
|
|
1988
|
-
{ name: "environmentId", description: "The environment, from list_environments", required: true }
|
|
1989
|
-
],
|
|
1990
|
-
buildInput: (p) => ({ environmentId: p.environmentId })
|
|
1991
|
-
},
|
|
1992
|
-
{
|
|
1993
|
-
name: "set_environment_variable",
|
|
1994
|
-
description: `Create or change an environment variable, by name, in one environment \u2014 global or service, same rules for both. Find the environmentId with list_environments. Where it belongs: a value shared by several services (a database host, an API base URL) goes ONCE in the active global environment; services inherit it. A value only one service needs goes in that service's environment (scope service, activated by the active global one), where it also overrides a global variable of the same name. Never hardcode what Runeya already knows: a service's own port is {{service.PORT}}, its own URL {{service.URL}}, another service's address {{services.<slug>.URL}} \u2014 a copied "3210" or "http://localhost:3211" breaks as soon as a port changes or the project runs on another machine. If the port a variable needs is not declared on its service, declare it there (update_service, ports) instead of writing the number. When a written value contains a port or URL of a project service, the response lists \`suggestions\`: rewrite the value with those references. Compose instead of copying: a value can reference another variable of the resolved environment as {{environment.KEY}} (e.g. "postgres://{{environment.DB_USER}}@{{environment.DB_HOST}}:5432"). ${BUILTINS_HELP} After writing, check the result with get_service_env (a service, optionally in another global environment) or resolve_environment (an environment alone). References are substituted in one pass: a reference to a variable whose own value is only a reference may stay unexpanded, so point at the variable that holds the actual value. $NAME is not a reference here: it only expands inside a shell command. pre and post are concatenated around the value, each resolved separately. You can replace a secret's value without reading it, and create a variable as secret. You cannot make a secret public nor make it readable by AI: that stays the user's decision. Never pass "***" as a value. The response never contains the value.`,
|
|
1995
|
-
route: "environment.setVariableBlind",
|
|
1996
|
-
method: "POST",
|
|
1997
|
-
params: [
|
|
1998
|
-
{ name: "environmentId", description: "The environment that holds the variable, from list_environments", required: true },
|
|
1999
|
-
{ name: "key", description: "The variable name, e.g. DATABASE_URL", required: true },
|
|
2000
|
-
{ name: "value", description: "The new value, possibly with {{environment.KEY}} references. Omit to leave it unchanged.", required: false },
|
|
2001
|
-
{ name: "pre", description: 'Text put before the value (e.g. "https://"). Omit to leave it unchanged.', required: false },
|
|
2002
|
-
{ name: "post", description: 'Text put after the value (e.g. "/api"). Omit to leave it unchanged.', required: false },
|
|
2003
|
-
{ name: "isSecret", description: '"true" to store it as a secret. On an existing public variable, makes it secret.', required: false },
|
|
2004
|
-
{ name: "description", description: "What the variable is for, in markdown", required: false }
|
|
2005
|
-
],
|
|
2006
|
-
buildInput: (p) => ({
|
|
2007
|
-
environmentId: p.environmentId,
|
|
2008
|
-
key: p.key,
|
|
2009
|
-
...p.value !== void 0 ? { value: p.value } : {},
|
|
2010
|
-
...p.pre !== void 0 ? { pre: p.pre } : {},
|
|
2011
|
-
...p.post !== void 0 ? { post: p.post } : {},
|
|
2012
|
-
...p.isSecret !== void 0 ? { isSecret: toBool(p.isSecret) } : {},
|
|
2013
|
-
...p.description !== void 0 ? { description: p.description } : {}
|
|
2014
|
-
})
|
|
2015
|
-
},
|
|
2016
|
-
{
|
|
2017
|
-
name: "set_environment_inheritance",
|
|
2018
|
-
description: "Switch whether a service environment inherits the variables of the global environment that activates it (the default), or is isolated from it and receives only its own variables. list_environments shows this as `isolated`. Isolating a service is unusual: it loses every shared variable of the project. Do it only when the user asks, and never to work around a variable \u2014 override it in the service environment instead.",
|
|
2019
|
-
route: "environment.setInheritanceBlind",
|
|
2020
|
-
method: "POST",
|
|
2021
|
-
params: [
|
|
2022
|
-
{ name: "environmentId", description: "A service environment (scope service), from list_environments", required: true },
|
|
2023
|
-
{ name: "inherit", description: '"true" to inherit from the global environment, "false" to isolate', required: true, schema: z3.boolean() }
|
|
2024
|
-
],
|
|
2025
|
-
buildInput: (p) => ({ environmentId: p.environmentId, inherit: toBool(p.inherit ?? "true") })
|
|
2026
|
-
},
|
|
2027
|
-
{
|
|
2028
|
-
name: "remove_environment_variable",
|
|
2029
|
-
description: "Delete an environment variable, by name, from one environment. Its value is lost.",
|
|
2030
|
-
route: "environment.removeVariableBlind",
|
|
2031
|
-
method: "POST",
|
|
2032
|
-
params: [
|
|
2033
|
-
{ name: "environmentId", description: "The environment that holds the variable", required: true },
|
|
2034
|
-
{ name: "key", description: "The variable name", required: true }
|
|
2035
|
-
],
|
|
2036
|
-
buildInput: (p) => ({ environmentId: p.environmentId, key: p.key }),
|
|
2037
|
-
destructive: true
|
|
2038
|
-
},
|
|
2039
|
-
{
|
|
2040
|
-
name: "get_service_metrics",
|
|
2041
|
-
description: "Read the CPU and memory currently used by a running service.",
|
|
2042
|
-
route: "process.metrics",
|
|
2043
|
-
method: "GET",
|
|
2044
|
-
params: [
|
|
2045
|
-
{ name: "serviceId", description: "The service ID", required: true },
|
|
2046
|
-
{ name: "agentId", description: "The agent ID hosting this service", required: true }
|
|
2047
|
-
],
|
|
2048
|
-
buildInput: (p) => ({ agentId: p.agentId, processId: p.serviceId })
|
|
2049
|
-
},
|
|
2050
|
-
{
|
|
2051
|
-
name: "list_agents",
|
|
2052
|
-
description: "List the agents connected to this Runeya, with their status and whether they run on this machine. Passphrases are never returned.",
|
|
2053
|
-
route: "agent.list",
|
|
2054
|
-
method: "GET",
|
|
2055
|
-
params: [],
|
|
2056
|
-
buildInput: () => void 0
|
|
2057
|
-
},
|
|
2058
|
-
{
|
|
2059
|
-
name: "list_projects",
|
|
2060
|
-
description: "List the projects known to this Runeya, with their ids and the services they hold.",
|
|
2061
|
-
route: "project.list",
|
|
2062
|
-
method: "GET",
|
|
2063
|
-
params: [],
|
|
2064
|
-
buildInput: () => void 0
|
|
2065
|
-
},
|
|
2066
|
-
{
|
|
2067
|
-
name: "get_project",
|
|
2068
|
-
description: "Read one project: its services, its active environment, its organization.",
|
|
2069
|
-
route: "project.get",
|
|
2070
|
-
method: "GET",
|
|
2071
|
-
params: [
|
|
2072
|
-
{ name: "projectId", description: "The project ID, from list_projects", required: true },
|
|
2073
|
-
{ name: "orgId", description: "Its organization. Needed only when the same project id exists in several.", required: false }
|
|
2074
|
-
],
|
|
2075
|
-
buildInput: (p) => ({ id: p.projectId, ...p.orgId ? { orgId: p.orgId } : {} })
|
|
2076
|
-
},
|
|
2077
|
-
{
|
|
2078
|
-
name: "list_project_paths",
|
|
2079
|
-
description: "Where each project lives on this machine. Use it to find the directory to work in before reading or editing files.",
|
|
2080
|
-
route: "project.localPaths",
|
|
2081
|
-
method: "GET",
|
|
2082
|
-
params: [],
|
|
2083
|
-
buildInput: () => void 0
|
|
2084
|
-
},
|
|
2085
|
-
{
|
|
2086
|
-
name: "git_status",
|
|
2087
|
-
description: "Read the git working tree of a service or a project: staged, modified and untracked files, current branch, ahead/behind counts.",
|
|
2088
|
-
route: "git.status",
|
|
2089
|
-
method: "GET",
|
|
2090
|
-
params: [
|
|
2091
|
-
{ name: "serviceId", description: "Target the repository of this service", required: false },
|
|
2092
|
-
{ name: "projectId", description: "Target the repository of this project, when no service is given", required: false },
|
|
2093
|
-
{ name: "agentId", description: "The agent hosting the repository", required: false },
|
|
2094
|
-
{ name: "orgId", description: "Its organization, when a project id alone is ambiguous", required: false }
|
|
2095
|
-
],
|
|
2096
|
-
buildInput: (p) => gitTarget(p)
|
|
2097
|
-
},
|
|
2098
|
-
{
|
|
2099
|
-
name: "git_log",
|
|
2100
|
-
description: "Read the recent commits of a service or project repository: hash, author, date, message.",
|
|
2101
|
-
route: "git.log",
|
|
2102
|
-
method: "GET",
|
|
2103
|
-
params: [
|
|
2104
|
-
{ name: "serviceId", description: "Target the repository of this service", required: false },
|
|
2105
|
-
{ name: "projectId", description: "Target the repository of this project, when no service is given", required: false },
|
|
2106
|
-
{ name: "agentId", description: "The agent hosting the repository", required: false },
|
|
2107
|
-
{ name: "orgId", description: "Its organization, when a project id alone is ambiguous", required: false },
|
|
2108
|
-
{ name: "limit", description: "How many commits to return (1-200). Default: 50.", required: false }
|
|
2109
|
-
],
|
|
2110
|
-
buildInput: (p) => ({ ...gitTarget(p), ...p.limit ? { limit: Number(p.limit) } : {} })
|
|
2111
|
-
},
|
|
2112
|
-
{
|
|
2113
|
-
name: "git_branches",
|
|
2114
|
-
description: "List the local and remote branches of a service or project repository.",
|
|
2115
|
-
route: "git.branches",
|
|
2116
|
-
method: "GET",
|
|
2117
|
-
params: [
|
|
2118
|
-
{ name: "serviceId", description: "Target the repository of this service", required: false },
|
|
2119
|
-
{ name: "projectId", description: "Target the repository of this project, when no service is given", required: false },
|
|
2120
|
-
{ name: "agentId", description: "The agent hosting the repository", required: false },
|
|
2121
|
-
{ name: "orgId", description: "Its organization, when a project id alone is ambiguous", required: false }
|
|
2122
|
-
],
|
|
2123
|
-
buildInput: (p) => gitTarget(p)
|
|
2124
|
-
},
|
|
2125
|
-
{
|
|
2126
|
-
name: "git_diff",
|
|
2127
|
-
description: "Read the diff of a service or project repository \u2014 everything, or one file. Use it to see what changed before describing or reviewing it.",
|
|
2128
|
-
route: "git.diff",
|
|
2129
|
-
method: "GET",
|
|
2130
|
-
params: [
|
|
2131
|
-
{ name: "serviceId", description: "Target the repository of this service", required: false },
|
|
2132
|
-
{ name: "projectId", description: "Target the repository of this project, when no service is given", required: false },
|
|
2133
|
-
{ name: "agentId", description: "The agent hosting the repository", required: false },
|
|
2134
|
-
{ name: "orgId", description: "Its organization, when a project id alone is ambiguous", required: false },
|
|
2135
|
-
{ name: "path", description: "Restrict the diff to this file path", required: false },
|
|
2136
|
-
{ name: "staged", description: 'Set to "true" to read the staged diff instead of the working tree', required: false },
|
|
2137
|
-
{ name: "untracked", description: 'Set to "true" to include untracked files', required: false }
|
|
2138
|
-
],
|
|
2139
|
-
buildInput: (p) => ({
|
|
2140
|
-
...gitTarget(p),
|
|
2141
|
-
...p.path ? { path: p.path } : {},
|
|
2142
|
-
...p.staged !== void 0 ? { staged: p.staged === "true" } : {},
|
|
2143
|
-
...p.untracked !== void 0 ? { untracked: p.untracked === "true" } : {}
|
|
2144
|
-
})
|
|
2145
|
-
},
|
|
2146
|
-
{
|
|
2147
|
-
name: "list_docs",
|
|
2148
|
-
description: "List the markdown documentation files of a scope, as a tree. Pair it with read_doc to answer from the project's own docs rather than from guesswork.",
|
|
2149
|
-
route: "wiki.list",
|
|
2150
|
-
method: "GET",
|
|
2151
|
-
params: [
|
|
2152
|
-
{ name: "scope", description: `"global" for this Runeya, or "service:<serviceId>" for one service's repository`, required: true }
|
|
2153
|
-
],
|
|
2154
|
-
buildInput: (p) => ({ scope: p.scope })
|
|
2155
|
-
},
|
|
2156
|
-
{
|
|
2157
|
-
name: "read_doc",
|
|
2158
|
-
description: "Read one markdown documentation file. Paths come from list_docs; only .md and .markdown can be read.",
|
|
2159
|
-
route: "wiki.read",
|
|
2160
|
-
method: "GET",
|
|
2161
|
-
params: [
|
|
2162
|
-
{ name: "scope", description: `"global" for this Runeya, or "service:<serviceId>" for one service's repository`, required: true },
|
|
2163
|
-
{ name: "path", description: "Relative path of the file, as returned by list_docs", required: true }
|
|
2164
|
-
],
|
|
2165
|
-
buildInput: (p) => ({ scope: p.scope, path: p.path })
|
|
2166
|
-
},
|
|
2167
|
-
{
|
|
2168
|
-
name: "get_server_logs",
|
|
2169
|
-
description: "Read Runeya's own recent log entries. Use it to explain why Runeya itself misbehaved \u2014 not to read a service's output, which is get_logs.",
|
|
2170
|
-
route: "diagnostics.recentLogs",
|
|
2171
|
-
method: "GET",
|
|
2172
|
-
params: [
|
|
2173
|
-
{ name: "limit", description: "How many entries to return (1-2000). Default: 500.", required: false }
|
|
2174
|
-
],
|
|
2175
|
-
buildInput: (p) => p.limit ? { limit: Number(p.limit) } : void 0
|
|
2176
|
-
},
|
|
2177
|
-
{
|
|
2178
|
-
name: "get_kanban_queue_state",
|
|
2179
|
-
description: "Read the state of the kanban task queue: what is running, what is waiting. Use it before queuing work, or to explain why a card has not started.",
|
|
2180
|
-
route: "kanbanQueue.getState",
|
|
2181
|
-
method: "GET",
|
|
2182
|
-
params: [],
|
|
2183
|
-
buildInput: () => void 0
|
|
2184
|
-
},
|
|
2185
|
-
{
|
|
2186
|
-
name: "export_project",
|
|
2187
|
-
description: "Read a project and every service it holds in one call, with secrets stripped out. Cheaper and safer than calling get_service for each service \u2014 prefer it whenever you need the whole picture of a project.",
|
|
2188
|
-
route: "project.export",
|
|
2189
|
-
method: "GET",
|
|
2190
|
-
params: [
|
|
2191
|
-
{ name: "projectId", description: "The project ID, from list_projects", required: true },
|
|
2192
|
-
{ name: "orgId", description: "Its organization. Needed only when the same project id exists in several.", required: false }
|
|
2193
|
-
],
|
|
2194
|
-
buildInput: (p) => ({ id: p.projectId, ...p.orgId ? { orgId: p.orgId } : {} })
|
|
2195
|
-
},
|
|
2196
|
-
{
|
|
2197
|
-
name: "git_remotes",
|
|
2198
|
-
description: "List the git remotes of a service or project repository, with their URLs.",
|
|
2199
|
-
route: "git.remotes",
|
|
2200
|
-
method: "GET",
|
|
2201
|
-
params: [
|
|
2202
|
-
{ name: "serviceId", description: "Target the repository of this service", required: false },
|
|
2203
|
-
{ name: "projectId", description: "Target the repository of this project, when no service is given", required: false },
|
|
2204
|
-
{ name: "agentId", description: "The agent hosting the repository", required: false },
|
|
2205
|
-
{ name: "orgId", description: "Its organization, when a project id alone is ambiguous", required: false }
|
|
2206
|
-
],
|
|
2207
|
-
buildInput: (p) => gitTarget(p)
|
|
2208
|
-
},
|
|
2209
|
-
{
|
|
2210
|
-
name: "git_stash_list",
|
|
2211
|
-
description: "List the stashes of a service or project repository. Useful before assuming work was lost: it may simply be stashed.",
|
|
2212
|
-
route: "git.stashList",
|
|
2213
|
-
method: "GET",
|
|
2214
|
-
params: [
|
|
2215
|
-
{ name: "serviceId", description: "Target the repository of this service", required: false },
|
|
2216
|
-
{ name: "projectId", description: "Target the repository of this project, when no service is given", required: false },
|
|
2217
|
-
{ name: "agentId", description: "The agent hosting the repository", required: false },
|
|
2218
|
-
{ name: "orgId", description: "Its organization, when a project id alone is ambiguous", required: false }
|
|
2219
|
-
],
|
|
2220
|
-
buildInput: (p) => gitTarget(p)
|
|
2221
|
-
},
|
|
2222
|
-
{
|
|
2223
|
-
name: "get_runeya_version",
|
|
2224
|
-
description: "Read the version of Runeya running here, the latest published one, and whether this install is up to date. Use it before blaming a bug on the code: the machine may simply be behind.",
|
|
2225
|
-
route: "health.versionInfo",
|
|
2226
|
-
method: "GET",
|
|
2227
|
-
params: [],
|
|
2228
|
-
buildInput: () => void 0
|
|
2229
|
-
},
|
|
2230
|
-
{
|
|
2231
|
-
name: "get_runeya_paths",
|
|
2232
|
-
description: "Read where Runeya keeps its things on this machine: its launch directory, its data directory, and the machine-wide directory holding cloud projects.",
|
|
2233
|
-
route: "settings.getPaths",
|
|
2234
|
-
method: "GET",
|
|
2235
|
-
params: [],
|
|
2236
|
-
buildInput: () => void 0
|
|
2237
|
-
},
|
|
2238
|
-
{
|
|
2239
|
-
name: "get_network_info",
|
|
2240
|
-
description: "Read where this Runeya listens (host and port) and whether it is reachable from the local network, with the URLs to use. Use it to give someone a working link instead of guessing one.",
|
|
2241
|
-
route: "settings.getNetwork",
|
|
2242
|
-
method: "GET",
|
|
2243
|
-
params: [],
|
|
2244
|
-
buildInput: () => void 0
|
|
2245
|
-
},
|
|
2246
|
-
{
|
|
2247
|
-
name: "list_runeya_instances",
|
|
2248
|
-
description: "List every Runeya answering on this machine, this one included, with its port and directory. Use it when a port is taken or when two instances seem to disagree.",
|
|
2249
|
-
route: "diagnostics.instances",
|
|
2250
|
-
method: "GET",
|
|
2251
|
-
params: [],
|
|
2252
|
-
buildInput: () => void 0
|
|
2253
|
-
},
|
|
2254
|
-
{
|
|
2255
|
-
name: "get_cloud_status",
|
|
2256
|
-
description: "Say whether this Runeya is linked to a cloud account, and to which cloud. A kanban tool failing for lack of a cloud link is explained here.",
|
|
2257
|
-
route: "cloudAuth.status",
|
|
2258
|
-
method: "GET",
|
|
2259
|
-
params: [],
|
|
2260
|
-
buildInput: () => void 0
|
|
2261
|
-
}
|
|
2262
|
-
];
|
|
2263
|
-
|
|
2264
|
-
// ../../packages/ai-capabilities/src/adapters/json-schema.ts
|
|
2265
|
-
import { z as z4 } from "zod";
|
|
2266
|
-
function paramJsonSchema(param) {
|
|
2267
|
-
if (!param.schema) return { type: "string", description: param.description };
|
|
2268
|
-
const { $schema: _ignored, ...schema } = z4.toJSONSchema(param.schema, { io: "input", unrepresentable: "any" });
|
|
2269
|
-
return { ...schema, description: param.description };
|
|
2270
|
-
}
|
|
2271
|
-
|
|
2272
|
-
// ../../packages/ai-capabilities/src/adapters/anthropic.ts
|
|
2273
|
-
function buildAnthropicTools(capabilities) {
|
|
2274
|
-
return capabilities.map((cap) => ({
|
|
2275
|
-
name: cap.name,
|
|
2276
|
-
description: cap.description,
|
|
2277
|
-
input_schema: {
|
|
2278
|
-
type: "object",
|
|
2279
|
-
properties: Object.fromEntries(
|
|
2280
|
-
cap.params.map((p) => [p.name, paramJsonSchema(p)])
|
|
2281
|
-
),
|
|
2282
|
-
required: cap.params.filter((p) => p.required).map((p) => p.name)
|
|
2283
|
-
}
|
|
2284
|
-
}));
|
|
2285
|
-
}
|
|
2286
|
-
|
|
2287
|
-
// ../../packages/ai-capabilities/src/adapters/openai.ts
|
|
2288
|
-
function buildOpenAITools(capabilities) {
|
|
2289
|
-
return capabilities.map((cap) => ({
|
|
2290
|
-
type: "function",
|
|
2291
|
-
function: {
|
|
2292
|
-
name: cap.name,
|
|
2293
|
-
description: cap.description,
|
|
2294
|
-
parameters: {
|
|
2295
|
-
type: "object",
|
|
2296
|
-
properties: Object.fromEntries(
|
|
2297
|
-
cap.params.map((p) => [p.name, paramJsonSchema(p)])
|
|
2298
|
-
),
|
|
2299
|
-
required: cap.params.filter((p) => p.required).map((p) => p.name)
|
|
2300
|
-
}
|
|
2301
|
-
}
|
|
2302
|
-
}));
|
|
2303
|
-
}
|
|
2304
|
-
|
|
2305
|
-
// ../../packages/ai-capabilities/src/adapters/prompt.ts
|
|
2306
|
-
function buildToolSafetyInstruction(capabilities) {
|
|
2307
|
-
const destructive = capabilities.filter((c) => c.destructive).map((c) => c.name);
|
|
2308
|
-
const withHints = capabilities.filter((c) => c.usageHint);
|
|
2309
|
-
const lines = ["## Tool use safety rules"];
|
|
2310
|
-
if (destructive.length > 0) {
|
|
2311
|
-
lines.push(`CRITICAL: Never call ${destructive.join(", ")} unless the user has EXPLICITLY and UNAMBIGUOUSLY requested it.`);
|
|
2312
|
-
lines.push(`- Only call destructive tools (${destructive.join(", ")}) when the user explicitly uses action words for a specific service.`);
|
|
2313
|
-
}
|
|
2314
|
-
if (withHints.length > 0) {
|
|
2315
|
-
lines.push("");
|
|
2316
|
-
lines.push("## Tool usage hints");
|
|
2317
|
-
for (const cap of withHints) {
|
|
2318
|
-
lines.push(`- ${cap.usageHint}`);
|
|
2319
|
-
}
|
|
2320
|
-
}
|
|
2321
|
-
return lines.join("\n");
|
|
2322
|
-
}
|
|
2323
|
-
|
|
2324
|
-
// ../../packages/ai-capabilities/src/adapters/mcp.ts
|
|
2325
|
-
import { z as z5 } from "zod";
|
|
2326
|
-
function toRawParams(input, cap) {
|
|
2327
|
-
const typed = new Set(cap?.params.filter((p) => p.schema).map((p) => p.name));
|
|
2328
|
-
return Object.fromEntries(Object.entries(input).map(([k, v]) => [
|
|
2329
|
-
k,
|
|
2330
|
-
v === null && typed.has(k) ? "null" : v == null ? void 0 : typeof v === "object" ? JSON.stringify(v) : String(v)
|
|
2331
|
-
]));
|
|
2332
|
-
}
|
|
2333
|
-
|
|
2334
|
-
// ../../packages/ai-capabilities/src/trpc-caller.ts
|
|
2335
|
-
async function callTrpc(baseUrl, route, method, input, authToken, fetchImpl = fetch) {
|
|
2336
|
-
const headers = {
|
|
2337
|
-
"Content-Type": "application/json",
|
|
2338
|
-
"Authorization": `Bearer ${authToken}`
|
|
2339
|
-
};
|
|
2340
|
-
const url = method === "GET" && input ? `${baseUrl}/api/trpc/${route}?input=${encodeURIComponent(JSON.stringify(input))}` : `${baseUrl}/api/trpc/${route}`;
|
|
2341
|
-
const res = await fetchImpl(url, {
|
|
2342
|
-
method,
|
|
2343
|
-
headers,
|
|
2344
|
-
...method === "POST" ? { body: JSON.stringify(input ?? {}) } : {},
|
|
2345
|
-
signal: AbortSignal.timeout(15e3)
|
|
2346
|
-
});
|
|
2347
|
-
const json = await res.json();
|
|
2348
|
-
if (json["error"]) throw new Error(JSON.stringify(json["error"]));
|
|
2349
|
-
const result = json["result"];
|
|
2350
|
-
return result?.["data"] ?? result ?? json;
|
|
2351
|
-
}
|
|
2352
|
-
async function runCapability(cap, baseUrl, params, authToken, fetchImpl = fetch) {
|
|
2353
|
-
const result = await callTrpc(baseUrl, cap.route, cap.method, cap.buildInput(params), authToken, fetchImpl);
|
|
2354
|
-
return cap.transformOutput ? cap.transformOutput(result) : result;
|
|
2355
|
-
}
|
|
2356
|
-
|
|
2357
|
-
// ../../packages/ai-capabilities/src/project-anchor.ts
|
|
2358
|
-
function applyProjectAnchor(cap, params, anchor) {
|
|
2359
|
-
const accepts = (name) => cap.params.some((p) => p.name === name);
|
|
2360
|
-
const anchored = { ...params };
|
|
2361
|
-
const mayAnchorOrg = !params["projectId"] || params["projectId"] === anchor.projectId;
|
|
2362
|
-
if (anchor.projectId && accepts("projectId") && !anchored["projectId"]) {
|
|
2363
|
-
anchored["projectId"] = anchor.projectId;
|
|
2364
|
-
}
|
|
2365
|
-
if (mayAnchorOrg && anchor.orgId && !anchored["orgId"] && accepts("orgId")) {
|
|
2366
|
-
anchored["orgId"] = anchor.orgId;
|
|
2367
|
-
}
|
|
2368
|
-
if (mayAnchorOrg && anchor.orgId && !anchored["organizationId"] && accepts("organizationId")) {
|
|
2369
|
-
anchored["organizationId"] = anchor.orgId;
|
|
2370
|
-
}
|
|
2371
|
-
return anchored;
|
|
2372
|
-
}
|
|
2373
|
-
|
|
2374
1401
|
// ../server/src/services/llms-txt-generator.ts
|
|
2375
1402
|
function generateAdminLlmsTxt(services, jwt, project) {
|
|
2376
1403
|
const lines = [];
|
|
@@ -2580,7 +1607,7 @@ async function executeTool(rawName, input, apiKey, authToken, anchor = {}) {
|
|
|
2580
1607
|
}
|
|
2581
1608
|
|
|
2582
1609
|
// ../server/src/trpc/routers/service.ts
|
|
2583
|
-
import { z as
|
|
1610
|
+
import { z as z3 } from "zod";
|
|
2584
1611
|
import { TRPCError as TRPCError2 } from "@trpc/server";
|
|
2585
1612
|
|
|
2586
1613
|
// ../server/src/services/audit-service.ts
|
|
@@ -2973,7 +2000,7 @@ async function resolveServiceVariables(service, opts = {}) {
|
|
|
2973
2000
|
}
|
|
2974
2001
|
return resolvedService;
|
|
2975
2002
|
}
|
|
2976
|
-
var
|
|
2003
|
+
var DockerConfigInput = DockerConfigSchema;
|
|
2977
2004
|
var serviceRouter = router({
|
|
2978
2005
|
/**
|
|
2979
2006
|
* Sans filtre, la réponse couvre TOUT le poste : `serviceStore.list()` rend
|
|
@@ -2990,10 +2017,10 @@ var serviceRouter = router({
|
|
|
2990
2017
|
* silencieux ferait croire au filtrage tout en rendant les services des
|
|
2991
2018
|
* autres organisations.
|
|
2992
2019
|
*/
|
|
2993
|
-
list: protectedProcedure.meta({ openapi: { method: "GET", path: "/services", tags: ["services"], summary: "List services (every project of the machine unless narrowed by project or organization)", protect: true } }).input(
|
|
2994
|
-
projectId:
|
|
2995
|
-
orgId:
|
|
2996
|
-
}).optional()).output(
|
|
2020
|
+
list: protectedProcedure.meta({ openapi: { method: "GET", path: "/services", tags: ["services"], summary: "List services (every project of the machine unless narrowed by project or organization)", protect: true } }).input(z3.object({
|
|
2021
|
+
projectId: z3.string().max(128).optional(),
|
|
2022
|
+
orgId: z3.string().max(128).nullable().optional()
|
|
2023
|
+
}).optional()).output(z3.any()).query(async ({ input, ctx }) => {
|
|
2997
2024
|
const all = await serviceStore.list();
|
|
2998
2025
|
const allowedIds = getAllowedServiceIds(ctx);
|
|
2999
2026
|
let filtered = allowedIds ? all.filter((s) => allowedIds.has(s.id)) : all;
|
|
@@ -3013,7 +2040,7 @@ var serviceRouter = router({
|
|
|
3013
2040
|
effectiveAgentId: await resolveEffectiveAgentId(s)
|
|
3014
2041
|
})));
|
|
3015
2042
|
}),
|
|
3016
|
-
get: protectedProcedure.meta({ openapi: { method: "GET", path: "/services/{id}", tags: ["services"], summary: "Get a service by ID", protect: true } }).input(
|
|
2043
|
+
get: protectedProcedure.meta({ openapi: { method: "GET", path: "/services/{id}", tags: ["services"], summary: "Get a service by ID", protect: true } }).input(z3.object({ id: z3.string().max(128) })).output(z3.any()).query(async ({ input, ctx }) => {
|
|
3017
2044
|
requireServiceAction(ctx, input.id, "service:read");
|
|
3018
2045
|
const service = await serviceStore.get(input.id);
|
|
3019
2046
|
if (!service) {
|
|
@@ -3039,11 +2066,11 @@ var serviceRouter = router({
|
|
|
3039
2066
|
* valeurs** — où chacune est définie, ce que ses cases disent, et si ce
|
|
3040
2067
|
* service la reçoit. Sans lui, un agent lisait l'effet sans la cause.
|
|
3041
2068
|
*/
|
|
3042
|
-
getEnv: protectedProcedure.meta({ openapi: { method: "GET", path: "/services/{id}/env", tags: ["services"], summary: "Get a service's environment variables (unshared secrets masked) plus the project's value-free variable inventory", protect: true } }).input(
|
|
3043
|
-
id:
|
|
2069
|
+
getEnv: protectedProcedure.meta({ openapi: { method: "GET", path: "/services/{id}/env", tags: ["services"], summary: "Get a service's environment variables (unshared secrets masked) plus the project's value-free variable inventory", protect: true } }).input(z3.object({
|
|
2070
|
+
id: z3.string().max(128),
|
|
3044
2071
|
// Un environnement global du projet où résoudre, sans l'activer. Absent : l'actif.
|
|
3045
|
-
environmentId:
|
|
3046
|
-
})).output(
|
|
2072
|
+
environmentId: z3.string().max(128).optional()
|
|
2073
|
+
})).output(z3.any()).query(async ({ input, ctx }) => {
|
|
3047
2074
|
requireServiceAction(ctx, input.id, "service:read");
|
|
3048
2075
|
const service = await serviceStore.get(input.id);
|
|
3049
2076
|
if (!service) {
|
|
@@ -3090,38 +2117,38 @@ var serviceRouter = router({
|
|
|
3090
2117
|
variables
|
|
3091
2118
|
};
|
|
3092
2119
|
}),
|
|
3093
|
-
create: protectedProcedure.meta({ openapi: { method: "POST", path: "/services", tags: ["services"], summary: "Create a new service", protect: true } }).output(
|
|
3094
|
-
|
|
3095
|
-
agentId:
|
|
3096
|
-
name:
|
|
3097
|
-
commands:
|
|
3098
|
-
cwd:
|
|
3099
|
-
ports:
|
|
3100
|
-
groups:
|
|
3101
|
-
description:
|
|
3102
|
-
docsPath:
|
|
3103
|
-
url:
|
|
3104
|
-
localUrls:
|
|
3105
|
-
url:
|
|
3106
|
-
port:
|
|
2120
|
+
create: protectedProcedure.meta({ openapi: { method: "POST", path: "/services", tags: ["services"], summary: "Create a new service", protect: true } }).output(z3.any()).input(
|
|
2121
|
+
z3.object({
|
|
2122
|
+
agentId: z3.string().max(128).optional(),
|
|
2123
|
+
name: z3.string().min(1).max(200),
|
|
2124
|
+
commands: z3.array(ServiceCommandSchema).max(50).optional(),
|
|
2125
|
+
cwd: z3.string().max(4096).optional(),
|
|
2126
|
+
ports: z3.array(z3.number().int().min(1).max(65535)).max(20).optional(),
|
|
2127
|
+
groups: z3.array(z3.string().max(200)).max(20).optional(),
|
|
2128
|
+
description: z3.string().max(2e3).optional(),
|
|
2129
|
+
docsPath: z3.string().max(4096).optional(),
|
|
2130
|
+
url: z3.string().max(2048).optional(),
|
|
2131
|
+
localUrls: z3.array(z3.object({
|
|
2132
|
+
url: z3.string().max(253),
|
|
2133
|
+
port: z3.number().int().min(1).max(65535)
|
|
3107
2134
|
})).max(20).optional(),
|
|
3108
|
-
openapiUrl:
|
|
3109
|
-
git:
|
|
3110
|
-
meta:
|
|
3111
|
-
runner:
|
|
3112
|
-
dockerConfig:
|
|
2135
|
+
openapiUrl: z3.string().max(2048).optional(),
|
|
2136
|
+
git: z3.object({ remote: z3.string().max(2048).optional(), home: z3.string().max(2048).optional() }).optional(),
|
|
2137
|
+
meta: z3.record(z3.string().max(256), z3.string().max(2e3)).optional().refine((obj) => !obj || Object.keys(obj).length <= 100, { message: "Too many meta keys (max 100)" }),
|
|
2138
|
+
runner: z3.enum(["native", "docker"]).optional().default("native"),
|
|
2139
|
+
dockerConfig: DockerConfigInput.optional(),
|
|
3113
2140
|
healthCheck: HealthCheckSchema.optional(),
|
|
3114
|
-
autoRestart:
|
|
3115
|
-
clearLogsOnStart:
|
|
2141
|
+
autoRestart: z3.boolean().optional().default(false),
|
|
2142
|
+
clearLogsOnStart: z3.boolean().optional(),
|
|
3116
2143
|
restartStrategy: RestartStrategySchema.optional(),
|
|
3117
|
-
maxRestarts:
|
|
3118
|
-
restartBackoffMs:
|
|
3119
|
-
orgId:
|
|
3120
|
-
logSources:
|
|
2144
|
+
maxRestarts: z3.number().int().nonnegative().optional(),
|
|
2145
|
+
restartBackoffMs: z3.number().int().positive().optional().default(1e3),
|
|
2146
|
+
orgId: z3.string().max(128).nullable().optional(),
|
|
2147
|
+
logSources: z3.array(LogSourceConfigSchema).max(20).optional(),
|
|
3121
2148
|
// Le projet qui va l'adopter : le service naît dans son coffre.
|
|
3122
|
-
projectId:
|
|
3123
|
-
shortcuts:
|
|
3124
|
-
parserIds:
|
|
2149
|
+
projectId: z3.string().max(128).optional(),
|
|
2150
|
+
shortcuts: z3.array(ServiceShortcutSchema).max(50).optional(),
|
|
2151
|
+
parserIds: z3.array(z3.string().max(128)).max(50).optional()
|
|
3125
2152
|
})
|
|
3126
2153
|
).mutation(async ({ input }) => {
|
|
3127
2154
|
if (input.agentId) {
|
|
@@ -3147,38 +2174,38 @@ var serviceRouter = router({
|
|
|
3147
2174
|
await auditService.log({ userId: "local", action: "create", entityType: "service", entityId: service.id, metadata: { name: input.name } });
|
|
3148
2175
|
return service;
|
|
3149
2176
|
}),
|
|
3150
|
-
update: protectedProcedure.meta({ openapi: { method: "PATCH", path: "/services/{id}", tags: ["services"], summary: "Update a service", protect: true } }).output(
|
|
3151
|
-
|
|
3152
|
-
id:
|
|
3153
|
-
agentId:
|
|
2177
|
+
update: protectedProcedure.meta({ openapi: { method: "PATCH", path: "/services/{id}", tags: ["services"], summary: "Update a service", protect: true } }).output(z3.any()).input(
|
|
2178
|
+
z3.object({
|
|
2179
|
+
id: z3.string().max(128),
|
|
2180
|
+
agentId: z3.string().max(128).nullable().optional(),
|
|
3154
2181
|
// null = clear (inherit from env)
|
|
3155
|
-
name:
|
|
3156
|
-
commands:
|
|
3157
|
-
cwd:
|
|
3158
|
-
ports:
|
|
3159
|
-
groups:
|
|
3160
|
-
description:
|
|
3161
|
-
docsPath:
|
|
3162
|
-
url:
|
|
3163
|
-
localUrls:
|
|
3164
|
-
url:
|
|
3165
|
-
port:
|
|
2182
|
+
name: z3.string().min(1).max(200).optional(),
|
|
2183
|
+
commands: z3.array(ServiceCommandSchema).max(50).optional(),
|
|
2184
|
+
cwd: z3.string().max(4096).nullable().optional(),
|
|
2185
|
+
ports: z3.array(z3.number().int().min(1).max(65535)).max(20).optional(),
|
|
2186
|
+
groups: z3.array(z3.string().max(200)).max(20).optional(),
|
|
2187
|
+
description: z3.string().max(2e3).optional(),
|
|
2188
|
+
docsPath: z3.string().max(4096).optional(),
|
|
2189
|
+
url: z3.string().max(2048).optional(),
|
|
2190
|
+
localUrls: z3.array(z3.object({
|
|
2191
|
+
url: z3.string().max(253),
|
|
2192
|
+
port: z3.number().int().min(1).max(65535)
|
|
3166
2193
|
})).max(20).optional(),
|
|
3167
|
-
openapiUrl:
|
|
3168
|
-
git:
|
|
3169
|
-
meta:
|
|
3170
|
-
runner:
|
|
3171
|
-
dockerConfig:
|
|
2194
|
+
openapiUrl: z3.string().max(2048).optional(),
|
|
2195
|
+
git: z3.object({ remote: z3.string().max(2048).optional(), home: z3.string().max(2048).optional() }).nullable().optional(),
|
|
2196
|
+
meta: z3.record(z3.string().max(256), z3.string().max(2e3)).nullable().optional().refine((obj) => !obj || Object.keys(obj).length <= 100, { message: "Too many meta keys (max 100)" }),
|
|
2197
|
+
runner: z3.enum(["native", "docker"]).optional(),
|
|
2198
|
+
dockerConfig: DockerConfigInput.optional(),
|
|
3172
2199
|
healthCheck: HealthCheckSchema.nullable().optional(),
|
|
3173
|
-
autoRestart:
|
|
3174
|
-
clearLogsOnStart:
|
|
2200
|
+
autoRestart: z3.boolean().optional(),
|
|
2201
|
+
clearLogsOnStart: z3.boolean().optional(),
|
|
3175
2202
|
restartStrategy: RestartStrategySchema.optional(),
|
|
3176
|
-
maxRestarts:
|
|
3177
|
-
restartBackoffMs:
|
|
3178
|
-
orgId:
|
|
3179
|
-
shortcuts:
|
|
3180
|
-
parserIds:
|
|
3181
|
-
logSources:
|
|
2203
|
+
maxRestarts: z3.number().int().nonnegative().optional(),
|
|
2204
|
+
restartBackoffMs: z3.number().int().positive().optional(),
|
|
2205
|
+
orgId: z3.string().max(128).nullable().optional(),
|
|
2206
|
+
shortcuts: z3.array(ServiceShortcutSchema).max(50).optional(),
|
|
2207
|
+
parserIds: z3.array(z3.string().max(128)).max(50).optional(),
|
|
2208
|
+
logSources: z3.array(LogSourceConfigSchema).max(20).optional()
|
|
3182
2209
|
})
|
|
3183
2210
|
).mutation(async ({ input }) => {
|
|
3184
2211
|
const existing = await serviceStore.get(input.id);
|
|
@@ -3234,7 +2261,7 @@ var serviceRouter = router({
|
|
|
3234
2261
|
await auditService.log({ userId: "local", action: "update", entityType: "service", entityId: input.id });
|
|
3235
2262
|
return { ...service, effectiveAgentId: await resolveEffectiveAgentId(service), stoppedForAgentChange };
|
|
3236
2263
|
}),
|
|
3237
|
-
delete: protectedProcedure.meta({ openapi: { method: "DELETE", path: "/services/{id}", tags: ["services"], summary: "Delete a service", protect: true } }).input(
|
|
2264
|
+
delete: protectedProcedure.meta({ openapi: { method: "DELETE", path: "/services/{id}", tags: ["services"], summary: "Delete a service", protect: true } }).input(z3.object({ id: z3.string().max(128) })).output(z3.object({ success: z3.literal(true) })).mutation(async ({ input }) => {
|
|
3238
2265
|
const deleted = await serviceStore.delete(input.id);
|
|
3239
2266
|
if (!deleted) {
|
|
3240
2267
|
throw new TRPCError2({ code: "NOT_FOUND", message: `Service ${input.id} not found` });
|
|
@@ -3242,7 +2269,7 @@ var serviceRouter = router({
|
|
|
3242
2269
|
await auditService.log({ userId: "local", action: "delete", entityType: "service", entityId: input.id });
|
|
3243
2270
|
return { success: true };
|
|
3244
2271
|
}),
|
|
3245
|
-
checkCwd: protectedProcedure.input(
|
|
2272
|
+
checkCwd: protectedProcedure.input(z3.object({ id: z3.string().max(128), checkReachability: z3.boolean().optional() })).query(async ({ input }) => {
|
|
3246
2273
|
const service = await serviceStore.get(input.id);
|
|
3247
2274
|
if (!service) {
|
|
3248
2275
|
throw new TRPCError2({ code: "NOT_FOUND", message: `Service ${input.id} not found` });
|
|
@@ -3275,7 +2302,7 @@ var serviceRouter = router({
|
|
|
3275
2302
|
}
|
|
3276
2303
|
return { exists, canClone, unresolvedVars: [], resolvedCwd, gitMismatch };
|
|
3277
2304
|
}),
|
|
3278
|
-
cloneRepository: protectedProcedure.input(
|
|
2305
|
+
cloneRepository: protectedProcedure.input(z3.object({ id: z3.string().max(128) })).mutation(async ({ input }) => {
|
|
3279
2306
|
const service = await serviceStore.get(input.id);
|
|
3280
2307
|
if (!service) {
|
|
3281
2308
|
throw new TRPCError2({ code: "NOT_FOUND", message: `Service ${input.id} not found` });
|
|
@@ -3679,9 +2706,9 @@ async function fetchProviderModels(provider, plaintextKey) {
|
|
|
3679
2706
|
async function vaultOfProject(projectId) {
|
|
3680
2707
|
if (!projectId) return void 0;
|
|
3681
2708
|
await ensureProjectsLoaded();
|
|
3682
|
-
const
|
|
3683
|
-
if (
|
|
3684
|
-
return
|
|
2709
|
+
const refs = refsOfProjectId(projectId);
|
|
2710
|
+
if (refs.length !== 1) return void 0;
|
|
2711
|
+
return refs[0]?.orgId ?? void 0;
|
|
3685
2712
|
}
|
|
3686
2713
|
|
|
3687
2714
|
// ../server/src/services/image-storage.service.ts
|
|
@@ -3870,7 +2897,7 @@ async function resolveImagesToBase64(images, contextId) {
|
|
|
3870
2897
|
}
|
|
3871
2898
|
|
|
3872
2899
|
// ../server/src/trpc/routers/cloud-auth.ts
|
|
3873
|
-
import { z as
|
|
2900
|
+
import { z as z5 } from "zod";
|
|
3874
2901
|
import { hostname } from "os";
|
|
3875
2902
|
import { basename } from "path";
|
|
3876
2903
|
import { TRPCError as TRPCError3 } from "@trpc/server";
|
|
@@ -4127,12 +3154,12 @@ var cloudSessionStore = new CloudSessionStore();
|
|
|
4127
3154
|
import { networkInterfaces } from "os";
|
|
4128
3155
|
import { readFile as readFile7, writeFile as writeFile4, mkdir as mkdir6 } from "fs/promises";
|
|
4129
3156
|
import { join as join6 } from "path";
|
|
4130
|
-
import { z as
|
|
3157
|
+
import { z as z4 } from "zod";
|
|
4131
3158
|
var LOOPBACK2 = "127.0.0.1";
|
|
4132
3159
|
var ANY = "0.0.0.0";
|
|
4133
3160
|
var NETWORK_FILE = "network.json";
|
|
4134
|
-
var NetworkFileSchema =
|
|
4135
|
-
instances:
|
|
3161
|
+
var NetworkFileSchema = z4.object({
|
|
3162
|
+
instances: z4.record(z4.string(), z4.object({ lanEnabled: z4.boolean().default(false) })).default({})
|
|
4136
3163
|
});
|
|
4137
3164
|
var httpServer = null;
|
|
4138
3165
|
function instanceKey() {
|
|
@@ -4257,12 +3284,12 @@ function getCloudApiUrl() {
|
|
|
4257
3284
|
return (env.CLOUD_URL ?? DEFAULT_CLOUD_API_URL).replace(/\/+$/, "");
|
|
4258
3285
|
}
|
|
4259
3286
|
async function orgCloudUrl(orgId) {
|
|
4260
|
-
const { readOrgClouds } = await import("./vault-resolver-
|
|
3287
|
+
const { readOrgClouds } = await import("./vault-resolver-E7KPKA5C.js");
|
|
4261
3288
|
const clouds = await readOrgClouds();
|
|
4262
3289
|
return (clouds[orgId] ?? getCloudApiUrl()).replace(/\/+$/, "");
|
|
4263
3290
|
}
|
|
4264
3291
|
async function accountForOrg(orgId) {
|
|
4265
|
-
const { readOrgAccounts, readOrgClouds } = await import("./vault-resolver-
|
|
3292
|
+
const { readOrgAccounts, readOrgClouds } = await import("./vault-resolver-E7KPKA5C.js");
|
|
4266
3293
|
const [stampedAccounts, stampedClouds, accounts] = await Promise.all([
|
|
4267
3294
|
readOrgAccounts(),
|
|
4268
3295
|
readOrgClouds(),
|
|
@@ -4425,15 +3452,15 @@ function isAllowedProxyPath(path) {
|
|
|
4425
3452
|
const [pathname] = path.split("?");
|
|
4426
3453
|
return PROXY_PREFIXES.some((p) => pathname === p || pathname.startsWith(p));
|
|
4427
3454
|
}
|
|
4428
|
-
var ScopeSchema =
|
|
4429
|
-
accountId:
|
|
3455
|
+
var ScopeSchema = z5.object({
|
|
3456
|
+
accountId: z5.string().min(1).max(64)
|
|
4430
3457
|
});
|
|
4431
3458
|
function scopeOf(input) {
|
|
4432
3459
|
return { accountId: input.accountId };
|
|
4433
3460
|
}
|
|
4434
3461
|
var cloudAuthRouter = router({
|
|
4435
3462
|
/** Build the cloud authorization URL to open in the browser. */
|
|
4436
|
-
startLogin: protectedProcedure.input(
|
|
3463
|
+
startLogin: protectedProcedure.input(z5.object({ returnTo: z5.string().url().max(2048) })).mutation(async ({ input }) => {
|
|
4437
3464
|
const callback = callbackForReturnTo(input.returnTo);
|
|
4438
3465
|
if (!callback) {
|
|
4439
3466
|
throw new TRPCError3({
|
|
@@ -4471,7 +3498,7 @@ var cloudAuthRouter = router({
|
|
|
4471
3498
|
* `null` quand rien ne rattache cette organisation à un compte de ce poste :
|
|
4472
3499
|
* l'interface l'affiche comme déconnectée, ce qu'elle est.
|
|
4473
3500
|
*/
|
|
4474
|
-
accountForOrg: protectedProcedure.input(
|
|
3501
|
+
accountForOrg: protectedProcedure.input(z5.object({ orgId: z5.string().min(1).max(128) })).query(async ({ input }) => ({ accountId: await accountForOrg(input.orgId) })),
|
|
4475
3502
|
/**
|
|
4476
3503
|
* Les comptes liés à ce poste, et l'organisation dont chacun répond.
|
|
4477
3504
|
*
|
|
@@ -4479,7 +3506,7 @@ var cloudAuthRouter = router({
|
|
|
4479
3506
|
* du projet ouvert, sous quel compte il se synchronise.
|
|
4480
3507
|
*/
|
|
4481
3508
|
accounts: protectedProcedure.query(async () => {
|
|
4482
|
-
const { readOrgAccounts } = await import("./vault-resolver-
|
|
3509
|
+
const { readOrgAccounts } = await import("./vault-resolver-E7KPKA5C.js");
|
|
4483
3510
|
return { accounts: await cloudSessionStore.list(), orgAccounts: await readOrgAccounts() };
|
|
4484
3511
|
}),
|
|
4485
3512
|
/** The cloud session (user + org), fetched with the stored token. */
|
|
@@ -4497,7 +3524,7 @@ var cloudAuthRouter = router({
|
|
|
4497
3524
|
const identity = await readCloudIdentity(account.cloudUrl, await cloudSessionStore.getToken(accountId) ?? "");
|
|
4498
3525
|
if (identity) {
|
|
4499
3526
|
const settled = await cloudSessionStore.describe(accountId, identity);
|
|
4500
|
-
const { renameOrgAccount } = await import("./vault-resolver-
|
|
3527
|
+
const { renameOrgAccount } = await import("./vault-resolver-E7KPKA5C.js");
|
|
4501
3528
|
await renameOrgAccount(accountId, settled);
|
|
4502
3529
|
}
|
|
4503
3530
|
}
|
|
@@ -4527,7 +3554,7 @@ var cloudAuthRouter = router({
|
|
|
4527
3554
|
* drops the session, and the local token is dropped here too, so nothing is
|
|
4528
3555
|
* left holding a dead credential.
|
|
4529
3556
|
*/
|
|
4530
|
-
revokeDevice: protectedProcedure.input(ScopeSchema.extend({ id:
|
|
3557
|
+
revokeDevice: protectedProcedure.input(ScopeSchema.extend({ id: z5.string().min(1).max(128) })).mutation(async ({ input }) => {
|
|
4531
3558
|
const { accountId } = input;
|
|
4532
3559
|
if (!accountId) throw new TRPCError3({ code: "PRECONDITION_FAILED", message: "No cloud account for this scope." });
|
|
4533
3560
|
const res = await cloudFetch2("/api/auth/device/revoke", {
|
|
@@ -4550,17 +3577,17 @@ var cloudAuthRouter = router({
|
|
|
4550
3577
|
* the cloud: the web UI asks its own server, which holds the credential.
|
|
4551
3578
|
*/
|
|
4552
3579
|
proxy: protectedProcedure.input(
|
|
4553
|
-
|
|
4554
|
-
path:
|
|
4555
|
-
method:
|
|
4556
|
-
query:
|
|
4557
|
-
body:
|
|
3580
|
+
z5.object({
|
|
3581
|
+
path: z5.string().min(1).max(512),
|
|
3582
|
+
method: z5.enum(["GET", "POST"]).default("GET"),
|
|
3583
|
+
query: z5.record(z5.string().max(128), z5.string().max(2048)).optional(),
|
|
3584
|
+
body: z5.unknown().optional(),
|
|
4558
3585
|
// Obligatoire, et seul : c'est la porte par laquelle passent tous les
|
|
4559
3586
|
// appels cloud de l'interface. La laisser optionnelle est ce qui a
|
|
4560
3587
|
// permis aux composables partagées de n'envoyer aucune portée pendant
|
|
4561
3588
|
// trente routes, et au serveur de retomber sur « le compte unique du
|
|
4562
3589
|
// poste » — muet dès qu'il y en a eu deux.
|
|
4563
|
-
accountId:
|
|
3590
|
+
accountId: z5.string().min(1).max(64)
|
|
4564
3591
|
})
|
|
4565
3592
|
).mutation(async ({ input }) => {
|
|
4566
3593
|
if (!isAllowedProxyPath(input.path)) {
|
|
@@ -5427,7 +4454,7 @@ function tailTranscript(opts) {
|
|
|
5427
4454
|
|
|
5428
4455
|
// ../server/src/services/ai-runners/claude-pty-runner.ts
|
|
5429
4456
|
async function getAgentManager() {
|
|
5430
|
-
const { agentManager: agentManager2 } = await import("./agent-manager-
|
|
4457
|
+
const { agentManager: agentManager2 } = await import("./agent-manager-R7BPQO6D.js");
|
|
5431
4458
|
return agentManager2;
|
|
5432
4459
|
}
|
|
5433
4460
|
function buildPtyArgs(params, sessionId, opts) {
|
|
@@ -5927,18 +4954,6 @@ var ClaudeCodeRunner = class {
|
|
|
5927
4954
|
import { spawn as spawn2 } from "child_process";
|
|
5928
4955
|
import { createInterface } from "readline";
|
|
5929
4956
|
import { EventEmitter } from "events";
|
|
5930
|
-
function resolveMcpArgs(env2) {
|
|
5931
|
-
if (!env2["RUNEYA_API_TOKEN"]) return [];
|
|
5932
|
-
try {
|
|
5933
|
-
return codexMcpArgs({
|
|
5934
|
-
RUNEYA_BASE_URL: env2["RUNEYA_BASE_URL"],
|
|
5935
|
-
RUNEYA_API_TOKEN: env2["RUNEYA_API_TOKEN"]
|
|
5936
|
-
});
|
|
5937
|
-
} catch (err) {
|
|
5938
|
-
console.warn("[codex-app-server] Failed to resolve MCP server path:", err.message);
|
|
5939
|
-
return [];
|
|
5940
|
-
}
|
|
5941
|
-
}
|
|
5942
4957
|
var CodexAppServerClient = class extends EventEmitter {
|
|
5943
4958
|
proc = null;
|
|
5944
4959
|
rl = null;
|
|
@@ -5960,7 +4975,10 @@ var CodexAppServerClient = class extends EventEmitter {
|
|
|
5960
4975
|
*/
|
|
5961
4976
|
async connect(runeyaEnv) {
|
|
5962
4977
|
const env2 = { ...process.env, ...runeyaEnv };
|
|
5963
|
-
const invocation = resolveCliInvocation("codex", [
|
|
4978
|
+
const invocation = resolveCliInvocation("codex", [
|
|
4979
|
+
...codexRuneyaMcpArgs({ RUNEYA_BASE_URL: env2["RUNEYA_BASE_URL"], RUNEYA_API_TOKEN: env2["RUNEYA_API_TOKEN"] }),
|
|
4980
|
+
"app-server"
|
|
4981
|
+
]);
|
|
5964
4982
|
this.proc = spawn2(invocation.command, invocation.args, {
|
|
5965
4983
|
windowsHide: true,
|
|
5966
4984
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -6121,7 +5139,7 @@ async function shutdownCodexAppServer() {
|
|
|
6121
5139
|
}
|
|
6122
5140
|
}
|
|
6123
5141
|
async function getAgentManager2() {
|
|
6124
|
-
const { agentManager: agentManager2 } = await import("./agent-manager-
|
|
5142
|
+
const { agentManager: agentManager2 } = await import("./agent-manager-R7BPQO6D.js");
|
|
6125
5143
|
return agentManager2;
|
|
6126
5144
|
}
|
|
6127
5145
|
function parseRuneyaCurlCommand(command) {
|
|
@@ -6554,24 +5572,70 @@ var CodexRunner = class {
|
|
|
6554
5572
|
}
|
|
6555
5573
|
};
|
|
6556
5574
|
|
|
5575
|
+
// ../server/src/services/cli-models.ts
|
|
5576
|
+
var CACHE_MS = 5 * 6e4;
|
|
5577
|
+
var MAX_PAGES = 10;
|
|
5578
|
+
var codexCache = /* @__PURE__ */ new Map();
|
|
5579
|
+
function parseCodexModels(result) {
|
|
5580
|
+
const data = result?.data;
|
|
5581
|
+
if (!Array.isArray(data)) return [];
|
|
5582
|
+
const models = [];
|
|
5583
|
+
for (const item of data) {
|
|
5584
|
+
if (!item || item.hidden === true || typeof item.model !== "string" || !item.model) continue;
|
|
5585
|
+
const label = typeof item.displayName === "string" && item.displayName ? item.displayName : item.model;
|
|
5586
|
+
models.push({ value: item.model, label });
|
|
5587
|
+
}
|
|
5588
|
+
return models;
|
|
5589
|
+
}
|
|
5590
|
+
async function fetchCodexModels(agentId) {
|
|
5591
|
+
const models = [];
|
|
5592
|
+
let cursor;
|
|
5593
|
+
for (let page = 0; page < MAX_PAGES; page++) {
|
|
5594
|
+
const res = await agentManager.agentMutation(
|
|
5595
|
+
agentId,
|
|
5596
|
+
"ai.codexRequest",
|
|
5597
|
+
{ method: "model/list", params: cursor ? { cursor } : {} }
|
|
5598
|
+
);
|
|
5599
|
+
models.push(...parseCodexModels(res?.result));
|
|
5600
|
+
cursor = res?.result?.nextCursor;
|
|
5601
|
+
if (!cursor) break;
|
|
5602
|
+
}
|
|
5603
|
+
return models;
|
|
5604
|
+
}
|
|
5605
|
+
async function listCliModels(runner, agentId) {
|
|
5606
|
+
if (runner === "claude-code") return CLAUDE_CODE_MODELS.map((m) => ({ value: m, label: m }));
|
|
5607
|
+
const target = agentId ?? agentManager.getDefaultAgentId();
|
|
5608
|
+
if (!target) return [];
|
|
5609
|
+
const cached = codexCache.get(target);
|
|
5610
|
+
if (cached && Date.now() - cached.at < CACHE_MS) return cached.models;
|
|
5611
|
+
try {
|
|
5612
|
+
const models = await fetchCodexModels(target);
|
|
5613
|
+
codexCache.set(target, { at: Date.now(), models });
|
|
5614
|
+
return models;
|
|
5615
|
+
} catch (err) {
|
|
5616
|
+
console.warn(`[cli-models] model/list a \xE9chou\xE9 sur l'agent ${target}:`, err.message);
|
|
5617
|
+
return [];
|
|
5618
|
+
}
|
|
5619
|
+
}
|
|
5620
|
+
|
|
6557
5621
|
// ../server/src/trpc/routers/chat.ts
|
|
6558
5622
|
function toConversationSummary(conv) {
|
|
6559
5623
|
const { messages, ...rest } = conv;
|
|
6560
5624
|
return { ...rest, messages: [], messagesOmitted: true, messageCount: messages.length };
|
|
6561
5625
|
}
|
|
6562
|
-
var MessageSchema =
|
|
6563
|
-
role:
|
|
6564
|
-
content:
|
|
5626
|
+
var MessageSchema = z6.object({
|
|
5627
|
+
role: z6.enum(["user", "assistant"]),
|
|
5628
|
+
content: z6.string().max(1e5)
|
|
6565
5629
|
});
|
|
6566
|
-
var ImagePartSchema =
|
|
6567
|
-
type:
|
|
6568
|
-
imageId:
|
|
6569
|
-
url:
|
|
6570
|
-
mimeType:
|
|
6571
|
-
altText:
|
|
5630
|
+
var ImagePartSchema = z6.object({
|
|
5631
|
+
type: z6.literal("image"),
|
|
5632
|
+
imageId: z6.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i),
|
|
5633
|
+
url: z6.string().max(500),
|
|
5634
|
+
mimeType: z6.string().max(100),
|
|
5635
|
+
altText: z6.string().max(500).optional()
|
|
6572
5636
|
});
|
|
6573
|
-
var ImagePartsSchema =
|
|
6574
|
-
var SectionNameSchema =
|
|
5637
|
+
var ImagePartsSchema = z6.array(ImagePartSchema).max(5).optional();
|
|
5638
|
+
var SectionNameSchema = z6.string().trim().min(1).max(80);
|
|
6575
5639
|
var LANGUAGE_INSTRUCTION = "Always respond in the same language the user writes in.";
|
|
6576
5640
|
async function buildSystemPrompt(apiKey) {
|
|
6577
5641
|
const allServices = await serviceStore.list();
|
|
@@ -6822,6 +5886,7 @@ async function buildCliSystemContext(conv, jwt) {
|
|
|
6822
5886
|
const resolvedServices = await Promise.all(ownServices.map((s) => resolveServiceVariables(s)));
|
|
6823
5887
|
let systemContext = generateAdminLlmsTxt(resolvedServices, jwt, project);
|
|
6824
5888
|
if (!conv?.isCompanion) systemContext += "\n\n" + companionSystemNote();
|
|
5889
|
+
else systemContext += "\n\n" + companionInstructions((await companionSettings()).prompt);
|
|
6825
5890
|
systemContext += await kanbanContextFor(conv, {
|
|
6826
5891
|
...ref?.id ? { projectId: ref.id } : {},
|
|
6827
5892
|
...ref?.orgId ? { orgId: ref.orgId } : {}
|
|
@@ -6943,7 +6008,7 @@ async function startCodexSession(convId, prompt, opts = {}) {
|
|
|
6943
6008
|
apiBaseUrl: `http://localhost:${env.PORT}`,
|
|
6944
6009
|
apiToken: opts.jwt ?? "",
|
|
6945
6010
|
model: opts.model ?? "",
|
|
6946
|
-
effort: "normal",
|
|
6011
|
+
effort: opts.effort ?? "normal",
|
|
6947
6012
|
signal: ac.signal,
|
|
6948
6013
|
skipTokenInstructions: true,
|
|
6949
6014
|
images: opts.images,
|
|
@@ -6967,24 +6032,24 @@ async function startCodexSession(convId, prompt, opts = {}) {
|
|
|
6967
6032
|
});
|
|
6968
6033
|
return { session, done };
|
|
6969
6034
|
}
|
|
6970
|
-
var MessagePartSchema =
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
type:
|
|
6035
|
+
var MessagePartSchema = z6.discriminatedUnion("type", [
|
|
6036
|
+
z6.object({ type: z6.literal("thinking"), text: z6.string().max(1e5) }),
|
|
6037
|
+
z6.object({ type: z6.literal("text"), text: z6.string().max(1e5) }),
|
|
6038
|
+
z6.object({
|
|
6039
|
+
type: z6.literal("tool"),
|
|
6975
6040
|
id: Id128Schema,
|
|
6976
6041
|
name: Id128Schema,
|
|
6977
|
-
input:
|
|
6978
|
-
rawInput:
|
|
6979
|
-
result:
|
|
6980
|
-
isError:
|
|
6981
|
-
pending:
|
|
6042
|
+
input: z6.record(z6.string(), z6.unknown()).optional(),
|
|
6043
|
+
rawInput: z6.string().max(1e4).optional(),
|
|
6044
|
+
result: z6.unknown().optional(),
|
|
6045
|
+
isError: z6.boolean().optional(),
|
|
6046
|
+
pending: z6.boolean()
|
|
6982
6047
|
})
|
|
6983
6048
|
]);
|
|
6984
|
-
var StoredMessageSchema =
|
|
6985
|
-
role:
|
|
6986
|
-
content:
|
|
6987
|
-
parts:
|
|
6049
|
+
var StoredMessageSchema = z6.object({
|
|
6050
|
+
role: z6.enum(["user", "assistant"]),
|
|
6051
|
+
content: z6.string().max(1e5),
|
|
6052
|
+
parts: z6.array(MessagePartSchema).max(200).optional()
|
|
6988
6053
|
});
|
|
6989
6054
|
async function conversationCwd(conv) {
|
|
6990
6055
|
return resolveConversationCwd(conv.id);
|
|
@@ -7001,7 +6066,7 @@ var chatRouter = router({
|
|
|
7001
6066
|
* et sans le même filtre il y reversait toutes les conversations de la
|
|
7002
6067
|
* machine, une seconde après un chargement pourtant filtré.
|
|
7003
6068
|
*/
|
|
7004
|
-
onChanged: protectedProcedure.input(
|
|
6069
|
+
onChanged: protectedProcedure.input(z6.object({
|
|
7005
6070
|
projectId: Id128Schema.optional(),
|
|
7006
6071
|
orgId: Id128Schema.nullable().optional()
|
|
7007
6072
|
}).optional()).subscription(async function* ({ input }) {
|
|
@@ -7053,7 +6118,7 @@ var chatRouter = router({
|
|
|
7053
6118
|
* reachable where they were written, without leaking into every other
|
|
7054
6119
|
* organization's projects.
|
|
7055
6120
|
*/
|
|
7056
|
-
list: protectedProcedure.input(
|
|
6121
|
+
list: protectedProcedure.input(z6.object({
|
|
7057
6122
|
projectId: Id128Schema.optional(),
|
|
7058
6123
|
orgId: Id128Schema.nullable().optional()
|
|
7059
6124
|
}).optional()).query(async ({ input }) => {
|
|
@@ -7061,24 +6126,24 @@ var chatRouter = router({
|
|
|
7061
6126
|
const convs = projectId ? await conversationStore.listForProject({ id: projectId, orgId: input?.orgId }) : await conversationStore.list();
|
|
7062
6127
|
return convs.map(toConversationSummary);
|
|
7063
6128
|
}),
|
|
7064
|
-
get: protectedProcedure.input(
|
|
6129
|
+
get: protectedProcedure.input(z6.object({ id: Id128Schema })).query(async ({ input }) => {
|
|
7065
6130
|
const conv = await conversationStore.get(input.id);
|
|
7066
6131
|
if (!conv) throw new TRPCError4({ code: "NOT_FOUND", message: "Conversation not found" });
|
|
7067
6132
|
return conv;
|
|
7068
6133
|
}),
|
|
7069
|
-
create: protectedProcedure.input(
|
|
6134
|
+
create: protectedProcedure.input(z6.object({
|
|
7070
6135
|
title: ShortString200Schema.optional(),
|
|
7071
|
-
isCli:
|
|
7072
|
-
runner:
|
|
6136
|
+
isCli: z6.boolean().optional(),
|
|
6137
|
+
runner: z6.enum(["claude-code", "codex"]).optional(),
|
|
7073
6138
|
providerId: Id128Schema.optional(),
|
|
7074
6139
|
scenarioId: Id128Schema.optional(),
|
|
7075
|
-
scenarioInput:
|
|
6140
|
+
scenarioInput: z6.string().max(1e5).optional(),
|
|
7076
6141
|
kanbanBoardId: Id128Schema.optional(),
|
|
7077
6142
|
kanbanCardId: Id128Schema.optional(),
|
|
7078
6143
|
// The project the conversation is about: only the caller knows which
|
|
7079
6144
|
// one it is looking at.
|
|
7080
6145
|
projectId: Id128Schema.optional(),
|
|
7081
|
-
orgId:
|
|
6146
|
+
orgId: z6.string().max(128).nullable().optional(),
|
|
7082
6147
|
// L'agent où la conversation travaille. Absent = agent par défaut.
|
|
7083
6148
|
agentId: Id128Schema.optional()
|
|
7084
6149
|
})).mutation(async ({ input }) => {
|
|
@@ -7091,10 +6156,13 @@ var chatRouter = router({
|
|
|
7091
6156
|
if (!scenario) throw new TRPCError4({ code: "NOT_FOUND", message: "Scenario not found" });
|
|
7092
6157
|
}
|
|
7093
6158
|
const machineSettings = await settingsManager.getSettings();
|
|
7094
|
-
const
|
|
6159
|
+
const companionDefaults = companionCreateDefaults(
|
|
6160
|
+
machineSettings.companion ?? { enabledByDefault: false },
|
|
6161
|
+
input.runner
|
|
6162
|
+
);
|
|
7095
6163
|
const extra = {
|
|
7096
6164
|
...input.agentId ? { agentId: input.agentId } : {},
|
|
7097
|
-
...
|
|
6165
|
+
...companionDefaults
|
|
7098
6166
|
};
|
|
7099
6167
|
const conv = await conversationStore.create(
|
|
7100
6168
|
input.title,
|
|
@@ -7118,13 +6186,13 @@ var chatRouter = router({
|
|
|
7118
6186
|
}
|
|
7119
6187
|
return conv;
|
|
7120
6188
|
}),
|
|
7121
|
-
update: protectedProcedure.input(
|
|
6189
|
+
update: protectedProcedure.input(z6.object({
|
|
7122
6190
|
id: Id128Schema,
|
|
7123
6191
|
title: ShortString200Schema.optional(),
|
|
7124
|
-
messages:
|
|
7125
|
-
contextUsage:
|
|
7126
|
-
inputTokens:
|
|
7127
|
-
contextWindow:
|
|
6192
|
+
messages: z6.array(StoredMessageSchema).max(500).optional(),
|
|
6193
|
+
contextUsage: z6.object({
|
|
6194
|
+
inputTokens: z6.number().int().nonnegative(),
|
|
6195
|
+
contextWindow: z6.number().int().positive()
|
|
7128
6196
|
}).optional()
|
|
7129
6197
|
})).mutation(async ({ input }) => {
|
|
7130
6198
|
const conv = await conversationStore.update(input.id, { title: input.title, messages: input.messages, contextUsage: input.contextUsage });
|
|
@@ -7138,10 +6206,14 @@ var chatRouter = router({
|
|
|
7138
6206
|
* messages, et un réglage qui voyage avec 500 messages se perdrait dans un
|
|
7139
6207
|
* patch dont ce n'est pas le sujet.
|
|
7140
6208
|
*/
|
|
7141
|
-
setCompanion: protectedProcedure.input(
|
|
6209
|
+
setCompanion: protectedProcedure.input(z6.object({
|
|
7142
6210
|
id: Id128Schema,
|
|
7143
|
-
enabled:
|
|
7144
|
-
runner:
|
|
6211
|
+
enabled: z6.boolean(),
|
|
6212
|
+
runner: z6.enum(["claude-code", "codex"]).optional(),
|
|
6213
|
+
/** Chaîne vide = modèle par défaut du runner. */
|
|
6214
|
+
model: z6.string().max(200).optional(),
|
|
6215
|
+
/** Chaîne vide = effort par défaut. */
|
|
6216
|
+
effort: z6.enum(["low", "normal", "high", ""]).optional()
|
|
7145
6217
|
})).mutation(async ({ input }) => {
|
|
7146
6218
|
const existing = await conversationStore.get(input.id);
|
|
7147
6219
|
if (!existing) throw new TRPCError4({ code: "NOT_FOUND", message: "Conversation not found" });
|
|
@@ -7150,7 +6222,9 @@ var chatRouter = router({
|
|
|
7150
6222
|
}
|
|
7151
6223
|
const conv = await conversationStore.update(input.id, {
|
|
7152
6224
|
companionEnabled: input.enabled,
|
|
7153
|
-
...input.runner ? { companionRunner: input.runner } : {}
|
|
6225
|
+
...input.runner ? { companionRunner: input.runner } : {},
|
|
6226
|
+
...input.model !== void 0 ? { companionModel: input.model } : {},
|
|
6227
|
+
...input.effort !== void 0 ? { companionEffort: input.effort } : {}
|
|
7154
6228
|
});
|
|
7155
6229
|
if (!conv) throw new TRPCError4({ code: "NOT_FOUND", message: "Conversation not found" });
|
|
7156
6230
|
if (!input.enabled) stopCompanion(conv);
|
|
@@ -7165,7 +6239,7 @@ var chatRouter = router({
|
|
|
7165
6239
|
* compagnon silencieux parce qu'il n'avait rien à dire et un message qui
|
|
7166
6240
|
* n'a pas pu être transmis se ressemblent parfaitement sans cette trace.
|
|
7167
6241
|
*/
|
|
7168
|
-
companionDelivery: protectedProcedure.input(
|
|
6242
|
+
companionDelivery: protectedProcedure.input(z6.object({ id: Id128Schema })).query(async ({ input }) => {
|
|
7169
6243
|
const conv = await conversationStore.get(input.id);
|
|
7170
6244
|
const companionId = conv?.companionConversationId;
|
|
7171
6245
|
const running = isCompanionThinking(input.id) || (companionId ? activeSessionRegistry.get(companionId)?.status === "running" : false);
|
|
@@ -7215,7 +6289,7 @@ var chatRouter = router({
|
|
|
7215
6289
|
* route emprunte exactement le chemin de livraison, sans le jugement, et
|
|
7216
6290
|
* rend PAR OÙ le message est passé.
|
|
7217
6291
|
*/
|
|
7218
|
-
testCompanionBridge: protectedProcedure.input(
|
|
6292
|
+
testCompanionBridge: protectedProcedure.input(z6.object({ id: Id128Schema })).mutation(async ({ input }) => {
|
|
7219
6293
|
const conv = await conversationStore.get(input.id);
|
|
7220
6294
|
if (!conv) throw new TRPCError4({ code: "NOT_FOUND", message: "Conversation not found" });
|
|
7221
6295
|
const route = await deliverToMainConversation(
|
|
@@ -7236,7 +6310,7 @@ var chatRouter = router({
|
|
|
7236
6310
|
* entier, bien plus qu'une requête ne doit rester ouverte. L'interface suit
|
|
7237
6311
|
* l'avancement par l'état poussé « il relit », déjà en place.
|
|
7238
6312
|
*/
|
|
7239
|
-
runCompanionNow: protectedProcedure.input(
|
|
6313
|
+
runCompanionNow: protectedProcedure.input(z6.object({ id: Id128Schema })).mutation(async ({ input }) => {
|
|
7240
6314
|
const conv = await conversationStore.get(input.id);
|
|
7241
6315
|
if (!conv) throw new TRPCError4({ code: "NOT_FOUND", message: "Conversation not found" });
|
|
7242
6316
|
if (conv.isCompanion) {
|
|
@@ -7253,7 +6327,7 @@ var chatRouter = router({
|
|
|
7253
6327
|
});
|
|
7254
6328
|
return { started: true };
|
|
7255
6329
|
}),
|
|
7256
|
-
delete: protectedProcedure.input(
|
|
6330
|
+
delete: protectedProcedure.input(z6.object({ id: Id128Schema })).mutation(async ({ input }) => {
|
|
7257
6331
|
const existing = await conversationStore.get(input.id);
|
|
7258
6332
|
if (!existing) throw new TRPCError4({ code: "NOT_FOUND", message: "Conversation not found" });
|
|
7259
6333
|
resetRelaunches(input.id);
|
|
@@ -7281,12 +6355,12 @@ var chatRouter = router({
|
|
|
7281
6355
|
(err) => console.error("[chat.delete] Image cleanup error:", err)
|
|
7282
6356
|
);
|
|
7283
6357
|
}),
|
|
7284
|
-
archive: protectedProcedure.input(
|
|
6358
|
+
archive: protectedProcedure.input(z6.object({ id: Id128Schema, archived: z6.boolean() })).mutation(async ({ input }) => {
|
|
7285
6359
|
const conv = await conversationStore.update(input.id, { archived: input.archived });
|
|
7286
6360
|
if (!conv) throw new TRPCError4({ code: "NOT_FOUND", message: "Conversation not found" });
|
|
7287
6361
|
return conv;
|
|
7288
6362
|
}),
|
|
7289
|
-
pin: protectedProcedure.input(
|
|
6363
|
+
pin: protectedProcedure.input(z6.object({ id: Id128Schema, pinned: z6.boolean() })).mutation(async ({ input }) => {
|
|
7290
6364
|
const conv = await conversationStore.setPinned(input.id, input.pinned);
|
|
7291
6365
|
if (!conv) throw new TRPCError4({ code: "NOT_FOUND", message: "Conversation not found" });
|
|
7292
6366
|
return conv;
|
|
@@ -7294,16 +6368,16 @@ var chatRouter = router({
|
|
|
7294
6368
|
// L'ordre ne vaut que pour les ids donnés : l'écran ne connaît que les
|
|
7295
6369
|
// conversations du projet courant, et les épinglées des autres projets
|
|
7296
6370
|
// n'ont pas à bouger parce qu'on a rangé celles-ci.
|
|
7297
|
-
reorderPinned: protectedProcedure.input(
|
|
6371
|
+
reorderPinned: protectedProcedure.input(z6.object({ ids: z6.array(Id128Schema).max(500) })).mutation(async ({ input }) => {
|
|
7298
6372
|
await conversationStore.reorderPinned(input.ids);
|
|
7299
6373
|
}),
|
|
7300
6374
|
// Ranger des conversations dans une section du projet, ou les en sortir
|
|
7301
6375
|
// (`sectionId: null`). Une conversation d'un autre projet est refusée :
|
|
7302
6376
|
// la section ne se verrait pas là où la conversation s'affiche.
|
|
7303
|
-
setSection: protectedProcedure.input(
|
|
6377
|
+
setSection: protectedProcedure.input(z6.object({
|
|
7304
6378
|
projectId: Id128Schema,
|
|
7305
6379
|
sectionId: Id128Schema.nullable(),
|
|
7306
|
-
ids:
|
|
6380
|
+
ids: z6.array(Id128Schema).max(500)
|
|
7307
6381
|
})).mutation(async ({ input }) => {
|
|
7308
6382
|
if (input.sectionId !== null && !await conversationSectionStore.get(input.projectId, input.sectionId)) {
|
|
7309
6383
|
throw new TRPCError4({ code: "NOT_FOUND", message: "Section not found" });
|
|
@@ -7319,28 +6393,28 @@ var chatRouter = router({
|
|
|
7319
6393
|
}),
|
|
7320
6394
|
// Les sections de la barre latérale, propres à chaque projet.
|
|
7321
6395
|
sections: router({
|
|
7322
|
-
list: protectedProcedure.input(
|
|
7323
|
-
create: protectedProcedure.input(
|
|
7324
|
-
rename: protectedProcedure.input(
|
|
6396
|
+
list: protectedProcedure.input(z6.object({ projectId: Id128Schema })).query(({ input }) => conversationSectionStore.list(input.projectId)),
|
|
6397
|
+
create: protectedProcedure.input(z6.object({ projectId: Id128Schema, name: SectionNameSchema })).mutation(({ input }) => conversationSectionStore.create(input.projectId, input.name)),
|
|
6398
|
+
rename: protectedProcedure.input(z6.object({ projectId: Id128Schema, id: Id128Schema, name: SectionNameSchema })).mutation(async ({ input }) => {
|
|
7325
6399
|
const section = await conversationSectionStore.rename(input.projectId, input.id, input.name);
|
|
7326
6400
|
if (!section) throw new TRPCError4({ code: "NOT_FOUND", message: "Section not found" });
|
|
7327
6401
|
return section;
|
|
7328
6402
|
}),
|
|
7329
6403
|
// Les conversations de la section retombent dans la liste, rien n'est supprimé.
|
|
7330
|
-
delete: protectedProcedure.input(
|
|
6404
|
+
delete: protectedProcedure.input(z6.object({ projectId: Id128Schema, id: Id128Schema })).mutation(async ({ input }) => {
|
|
7331
6405
|
if (!await conversationSectionStore.remove(input.projectId, input.id)) {
|
|
7332
6406
|
throw new TRPCError4({ code: "NOT_FOUND", message: "Section not found" });
|
|
7333
6407
|
}
|
|
7334
6408
|
await conversationStore.clearSection(input.id);
|
|
7335
6409
|
}),
|
|
7336
|
-
reorder: protectedProcedure.input(
|
|
6410
|
+
reorder: protectedProcedure.input(z6.object({ projectId: Id128Schema, ids: z6.array(Id128Schema).max(200) })).mutation(({ input }) => conversationSectionStore.reorder(input.projectId, input.ids))
|
|
7337
6411
|
}),
|
|
7338
|
-
listModels: protectedProcedure.input(
|
|
6412
|
+
listModels: protectedProcedure.input(z6.object({
|
|
7339
6413
|
providerId: Id128Schema.optional(),
|
|
7340
6414
|
// Le projet dit de quelle organisation lire les fournisseurs ; absent,
|
|
7341
6415
|
// ce sont ceux du poste.
|
|
7342
6416
|
projectId: Id128Schema.optional(),
|
|
7343
|
-
orgId:
|
|
6417
|
+
orgId: z6.string().max(128).nullable().optional()
|
|
7344
6418
|
}).optional()).query(async ({ input }) => {
|
|
7345
6419
|
const active = await getActiveProvider(
|
|
7346
6420
|
input?.providerId,
|
|
@@ -7353,7 +6427,16 @@ var chatRouter = router({
|
|
|
7353
6427
|
return [];
|
|
7354
6428
|
}
|
|
7355
6429
|
}),
|
|
7356
|
-
|
|
6430
|
+
/**
|
|
6431
|
+
* Les modèles proposés pour un runner CLI : alias fixes pour Claude Code,
|
|
6432
|
+
* `model/list` de l'app-server pour Codex, sur l'agent visé (celui par
|
|
6433
|
+
* défaut sinon). Liste vide si Codex ne répond pas.
|
|
6434
|
+
*/
|
|
6435
|
+
listCliModels: protectedProcedure.input(z6.object({
|
|
6436
|
+
runner: z6.enum(["claude-code", "codex"]),
|
|
6437
|
+
agentId: Id128Schema.optional()
|
|
6438
|
+
})).query(async ({ input }) => ({ models: await listCliModels(input.runner, input.agentId) })),
|
|
6439
|
+
checkCliAvailability: protectedProcedure.input(z6.object({ agentId: Id128Schema.optional() }).optional()).query(async ({ input }) => {
|
|
7357
6440
|
if (input?.agentId) {
|
|
7358
6441
|
try {
|
|
7359
6442
|
const res = await agentManager.agentQuery(
|
|
@@ -7371,12 +6454,12 @@ var chatRouter = router({
|
|
|
7371
6454
|
]);
|
|
7372
6455
|
return { available: claudeOk, codexAvailable: codexOk };
|
|
7373
6456
|
}),
|
|
7374
|
-
enhanceScenarioPrompt: protectedProcedure.input(
|
|
7375
|
-
text:
|
|
6457
|
+
enhanceScenarioPrompt: protectedProcedure.input(z6.object({
|
|
6458
|
+
text: z6.string().max(1e4),
|
|
7376
6459
|
providerId: Id128Schema.optional(),
|
|
7377
|
-
model:
|
|
6460
|
+
model: z6.string().max(200).optional(),
|
|
7378
6461
|
projectId: Id128Schema.optional(),
|
|
7379
|
-
orgId:
|
|
6462
|
+
orgId: z6.string().max(128).nullable().optional()
|
|
7380
6463
|
})).mutation(async ({ input }) => {
|
|
7381
6464
|
const active = await getActiveProvider(
|
|
7382
6465
|
input.providerId,
|
|
@@ -7419,22 +6502,22 @@ Return ONLY the improved text, no explanation, no preamble.`;
|
|
|
7419
6502
|
}),
|
|
7420
6503
|
listClaudeCodeModels: protectedProcedure.query(() => ["opus", "sonnet", "haiku"]),
|
|
7421
6504
|
getStreamingStatus: protectedProcedure.query(() => activeSessionRegistry.listActive()),
|
|
7422
|
-
stopSession: protectedProcedure.input(
|
|
6505
|
+
stopSession: protectedProcedure.input(z6.object({ conversationId: ConversationIdSchema })).mutation(({ input }) => {
|
|
7423
6506
|
if (process.env.RUNEYA_DEBUG) console.log("[chat]: stopSession");
|
|
7424
6507
|
const killed = activeSessionRegistry.kill(input.conversationId);
|
|
7425
6508
|
if (!killed) throw new TRPCError4({ code: "NOT_FOUND", message: "No active session for this conversation" });
|
|
7426
6509
|
return { ok: true };
|
|
7427
6510
|
}),
|
|
7428
|
-
streamViaClaudeCode: protectedProcedure.input(
|
|
6511
|
+
streamViaClaudeCode: protectedProcedure.input(z6.object({
|
|
7429
6512
|
conversationId: ConversationIdSchema,
|
|
7430
|
-
prompt:
|
|
7431
|
-
contextNote:
|
|
6513
|
+
prompt: z6.string().max(1e5),
|
|
6514
|
+
contextNote: z6.string().max(2e5).optional(),
|
|
7432
6515
|
model: ShortString200Schema.optional(),
|
|
7433
|
-
effort:
|
|
7434
|
-
reconnect:
|
|
6516
|
+
effort: z6.enum(["low", "medium", "high"]).optional(),
|
|
6517
|
+
reconnect: z6.boolean().optional(),
|
|
7435
6518
|
agentId: Id128Schema.optional(),
|
|
7436
|
-
environmentId:
|
|
7437
|
-
imageIds:
|
|
6519
|
+
environmentId: z6.string().max(128).optional(),
|
|
6520
|
+
imageIds: z6.array(z6.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)).max(5).optional(),
|
|
7438
6521
|
imageParts: ImagePartsSchema
|
|
7439
6522
|
})).subscription(async function* ({ input, ctx, signal }) {
|
|
7440
6523
|
if (process.env.RUNEYA_DEBUG) console.log("[chat]: Reconnect");
|
|
@@ -7536,15 +6619,15 @@ ${imagePaths.map((p) => `Image: ${p}`).join("\n")}` : cliPrompt;
|
|
|
7536
6619
|
if (process.env.RUNEYA_DEBUG) console.log("[chat]: drainSession...");
|
|
7537
6620
|
yield* drainSession(session, signal, false);
|
|
7538
6621
|
}),
|
|
7539
|
-
streamViaCodex: protectedProcedure.input(
|
|
6622
|
+
streamViaCodex: protectedProcedure.input(z6.object({
|
|
7540
6623
|
conversationId: ConversationIdSchema,
|
|
7541
|
-
prompt:
|
|
7542
|
-
contextNote:
|
|
6624
|
+
prompt: z6.string().max(1e5),
|
|
6625
|
+
contextNote: z6.string().max(2e5).optional(),
|
|
7543
6626
|
model: ShortString200Schema.optional(),
|
|
7544
|
-
reconnect:
|
|
6627
|
+
reconnect: z6.boolean().optional(),
|
|
7545
6628
|
agentId: Id128Schema.optional(),
|
|
7546
|
-
environmentId:
|
|
7547
|
-
imageIds:
|
|
6629
|
+
environmentId: z6.string().max(128).optional(),
|
|
6630
|
+
imageIds: z6.array(z6.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)).max(5).optional(),
|
|
7548
6631
|
imageParts: ImagePartsSchema
|
|
7549
6632
|
})).subscription(async function* ({ input, ctx, signal }) {
|
|
7550
6633
|
const existingSession = activeSessionRegistry.get(input.conversationId);
|
|
@@ -7614,13 +6697,13 @@ ${input.prompt}` : input.prompt;
|
|
|
7614
6697
|
});
|
|
7615
6698
|
yield* drainSession(session, signal, false);
|
|
7616
6699
|
}),
|
|
7617
|
-
send: protectedProcedure.input(
|
|
6700
|
+
send: protectedProcedure.input(z6.object({
|
|
7618
6701
|
conversationId: ConversationIdSchema,
|
|
7619
|
-
messages:
|
|
6702
|
+
messages: z6.array(MessageSchema).min(0).max(100),
|
|
7620
6703
|
model: ShortString200Schema.optional(),
|
|
7621
|
-
contextNote:
|
|
7622
|
-
reconnect:
|
|
7623
|
-
imageIds:
|
|
6704
|
+
contextNote: z6.string().max(2e5).optional(),
|
|
6705
|
+
reconnect: z6.boolean().optional(),
|
|
6706
|
+
imageIds: z6.array(z6.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)).max(5).optional(),
|
|
7624
6707
|
imageParts: ImagePartsSchema
|
|
7625
6708
|
})).subscription(async function* ({ input, ctx, signal }) {
|
|
7626
6709
|
const existingSession = activeSessionRegistry.get(input.conversationId);
|
|
@@ -7737,25 +6820,25 @@ ${input.prompt}` : input.prompt;
|
|
|
7737
6820
|
// ── PTY passthrough (interactive Claude Code session) ────────────────────
|
|
7738
6821
|
pty: router({
|
|
7739
6822
|
/** Start a PTY session running `claude --resume <sessionId>` (or fresh). */
|
|
7740
|
-
start: protectedProcedure.input(
|
|
7741
|
-
agentId:
|
|
7742
|
-
sessionId:
|
|
7743
|
-
runner:
|
|
7744
|
-
resume:
|
|
7745
|
-
model:
|
|
7746
|
-
cwd:
|
|
6823
|
+
start: protectedProcedure.input(z6.object({
|
|
6824
|
+
agentId: z6.string().max(128).optional(),
|
|
6825
|
+
sessionId: z6.string().max(128).optional(),
|
|
6826
|
+
runner: z6.enum(["claude-code", "codex"]).default("claude-code"),
|
|
6827
|
+
resume: z6.boolean().default(false),
|
|
6828
|
+
model: z6.string().max(128).optional(),
|
|
6829
|
+
cwd: z6.string().max(4096).optional(),
|
|
7747
6830
|
/** Anchors the session when no explicit cwd is given. */
|
|
7748
|
-
serviceId:
|
|
6831
|
+
serviceId: z6.string().max(128).optional(),
|
|
7749
6832
|
projectId: Id128Schema.optional(),
|
|
7750
|
-
orgId:
|
|
7751
|
-
cols:
|
|
7752
|
-
rows:
|
|
7753
|
-
enableMcp:
|
|
7754
|
-
apiBaseUrl:
|
|
7755
|
-
environmentId:
|
|
7756
|
-
attachedContexts:
|
|
7757
|
-
label:
|
|
7758
|
-
text:
|
|
6833
|
+
orgId: z6.string().max(128).nullable().optional(),
|
|
6834
|
+
cols: z6.number().int().min(1).max(1e3).default(120),
|
|
6835
|
+
rows: z6.number().int().min(1).max(1e3).default(30),
|
|
6836
|
+
enableMcp: z6.boolean().default(false),
|
|
6837
|
+
apiBaseUrl: z6.string().max(512).optional(),
|
|
6838
|
+
environmentId: z6.string().max(128).optional(),
|
|
6839
|
+
attachedContexts: z6.array(z6.object({
|
|
6840
|
+
label: z6.string().max(200),
|
|
6841
|
+
text: z6.string().max(1e6)
|
|
7759
6842
|
})).max(20).optional()
|
|
7760
6843
|
})).mutation(async ({ input, ctx }) => {
|
|
7761
6844
|
const t0 = Date.now();
|
|
@@ -7917,10 +7000,10 @@ Context:
|
|
|
7917
7000
|
return { spawnId: res.spawnId, agentId, reattached: false };
|
|
7918
7001
|
}),
|
|
7919
7002
|
/** Subscribe to PTY output stream (raw text with ANSI). */
|
|
7920
|
-
stream: protectedProcedure.input(
|
|
7921
|
-
agentId:
|
|
7922
|
-
spawnId:
|
|
7923
|
-
fromOffset:
|
|
7003
|
+
stream: protectedProcedure.input(z6.object({
|
|
7004
|
+
agentId: z6.string().max(128).optional(),
|
|
7005
|
+
spawnId: z6.string().max(128),
|
|
7006
|
+
fromOffset: z6.number().int().min(0).default(0)
|
|
7924
7007
|
})).subscription(async function* ({ input, signal }) {
|
|
7925
7008
|
const agentId = input.agentId ?? agentManager.getDefaultAgentId();
|
|
7926
7009
|
if (!agentId) throw new TRPCError4({ code: "PRECONDITION_FAILED", message: "No agent available" });
|
|
@@ -7975,10 +7058,10 @@ Context:
|
|
|
7975
7058
|
}
|
|
7976
7059
|
}),
|
|
7977
7060
|
/** Write input to a PTY session (keystrokes from xterm). */
|
|
7978
|
-
write: protectedProcedure.input(
|
|
7979
|
-
agentId:
|
|
7980
|
-
spawnId:
|
|
7981
|
-
data:
|
|
7061
|
+
write: protectedProcedure.input(z6.object({
|
|
7062
|
+
agentId: z6.string().max(128).optional(),
|
|
7063
|
+
spawnId: z6.string().max(128),
|
|
7064
|
+
data: z6.string().max(1e6)
|
|
7982
7065
|
})).mutation(async ({ input }) => {
|
|
7983
7066
|
const agentId = input.agentId ?? agentManager.getDefaultAgentId();
|
|
7984
7067
|
if (!agentId) throw new TRPCError4({ code: "PRECONDITION_FAILED", message: "No agent available" });
|
|
@@ -7988,11 +7071,11 @@ Context:
|
|
|
7988
7071
|
});
|
|
7989
7072
|
}),
|
|
7990
7073
|
/** Resize a PTY session. */
|
|
7991
|
-
resize: protectedProcedure.input(
|
|
7992
|
-
agentId:
|
|
7993
|
-
spawnId:
|
|
7994
|
-
cols:
|
|
7995
|
-
rows:
|
|
7074
|
+
resize: protectedProcedure.input(z6.object({
|
|
7075
|
+
agentId: z6.string().max(128).optional(),
|
|
7076
|
+
spawnId: z6.string().max(128),
|
|
7077
|
+
cols: z6.number().int().min(1).max(1e3),
|
|
7078
|
+
rows: z6.number().int().min(1).max(1e3)
|
|
7996
7079
|
})).mutation(async ({ input }) => {
|
|
7997
7080
|
const agentId = input.agentId ?? agentManager.getDefaultAgentId();
|
|
7998
7081
|
if (!agentId) throw new TRPCError4({ code: "PRECONDITION_FAILED", message: "No agent available" });
|
|
@@ -8008,11 +7091,11 @@ Context:
|
|
|
8008
7091
|
* picks it up. Returns the tmp path and which clipboard method succeeded
|
|
8009
7092
|
* (null if none — caller should inject `@<path>` instead of Ctrl+V).
|
|
8010
7093
|
*/
|
|
8011
|
-
pasteImage: protectedProcedure.input(
|
|
8012
|
-
agentId:
|
|
8013
|
-
sessionId:
|
|
8014
|
-
mimeType:
|
|
8015
|
-
base64:
|
|
7094
|
+
pasteImage: protectedProcedure.input(z6.object({
|
|
7095
|
+
agentId: z6.string().max(128).optional(),
|
|
7096
|
+
sessionId: z6.string().max(128).optional(),
|
|
7097
|
+
mimeType: z6.string().max(64),
|
|
7098
|
+
base64: z6.string().max(15e6)
|
|
8016
7099
|
})).mutation(async ({ input }) => {
|
|
8017
7100
|
const agentId = input.agentId ?? agentManager.getDefaultAgentId();
|
|
8018
7101
|
if (!agentId) throw new TRPCError4({ code: "PRECONDITION_FAILED", message: "No agent available" });
|
|
@@ -8030,7 +7113,7 @@ Context:
|
|
|
8030
7113
|
* Read the transcript Claude Code stores on disk for a given session.
|
|
8031
7114
|
* Returns parsed JSONL entries (user / assistant messages, tool uses, etc.).
|
|
8032
7115
|
*/
|
|
8033
|
-
transcript: protectedProcedure.input(
|
|
7116
|
+
transcript: protectedProcedure.input(z6.object({ sessionId: z6.string().max(128) })).query(async ({ input }) => {
|
|
8034
7117
|
return readClaudeTranscript(input.sessionId);
|
|
8035
7118
|
}),
|
|
8036
7119
|
/**
|
|
@@ -8038,9 +7121,9 @@ Context:
|
|
|
8038
7121
|
* when was the transcript JSONL last touched? Used by the non-PTY view
|
|
8039
7122
|
* to show a "Claude is thinking…" indicator while output streams.
|
|
8040
7123
|
*/
|
|
8041
|
-
activity: protectedProcedure.input(
|
|
8042
|
-
agentId:
|
|
8043
|
-
sessionId:
|
|
7124
|
+
activity: protectedProcedure.input(z6.object({
|
|
7125
|
+
agentId: z6.string().max(128).optional(),
|
|
7126
|
+
sessionId: z6.string().max(128)
|
|
8044
7127
|
})).query(async ({ input }) => {
|
|
8045
7128
|
const agentId = input.agentId ?? agentManager.getDefaultAgentId();
|
|
8046
7129
|
let running = false;
|
|
@@ -8059,14 +7142,15 @@ Context:
|
|
|
8059
7142
|
}
|
|
8060
7143
|
const transcriptActivityAt = getLastTranscriptActivity(input.sessionId);
|
|
8061
7144
|
const lastActivityAt = lastChunkAt && transcriptActivityAt ? Math.max(lastChunkAt, transcriptActivityAt) : lastChunkAt ?? transcriptActivityAt;
|
|
8062
|
-
|
|
7145
|
+
const idleMs = lastActivityAt === null ? null : Math.max(0, Date.now() - lastActivityAt);
|
|
7146
|
+
return { running, lastActivityAt, idleMs };
|
|
8063
7147
|
}),
|
|
8064
7148
|
/**
|
|
8065
7149
|
* Convert the on-disk Claude transcript into Runeya Message[] and persist
|
|
8066
7150
|
* them on the conversation, so the non-PTY chat view stays in sync.
|
|
8067
7151
|
* Uses the conversation id as session id (PTY sessions are spawned that way).
|
|
8068
7152
|
*/
|
|
8069
|
-
syncTranscript: protectedProcedure.input(
|
|
7153
|
+
syncTranscript: protectedProcedure.input(z6.object({ conversationId: ConversationIdSchema })).mutation(async ({ input }) => {
|
|
8070
7154
|
const conv = await conversationStore.get(input.conversationId);
|
|
8071
7155
|
if (!conv) {
|
|
8072
7156
|
throw new TRPCError4({ code: "NOT_FOUND", message: `Conversation ${input.conversationId} not found` });
|
|
@@ -8080,14 +7164,14 @@ Context:
|
|
|
8080
7164
|
* with the given sessionId. Used to benchmark the PTY → tRPC → xterm.js
|
|
8081
7165
|
* pipeline. Open the conversation in PTY mode to attach to it.
|
|
8082
7166
|
*/
|
|
8083
|
-
debugStress: protectedProcedure.input(
|
|
8084
|
-
sessionId:
|
|
8085
|
-
agentId:
|
|
8086
|
-
bytesPerSec:
|
|
8087
|
-
chunkSize:
|
|
8088
|
-
durationMs:
|
|
8089
|
-
cols:
|
|
8090
|
-
rows:
|
|
7167
|
+
debugStress: protectedProcedure.input(z6.object({
|
|
7168
|
+
sessionId: z6.string().max(128),
|
|
7169
|
+
agentId: z6.string().max(128).optional(),
|
|
7170
|
+
bytesPerSec: z6.number().int().min(100).max(1e7).default(5e4),
|
|
7171
|
+
chunkSize: z6.number().int().min(1).max(65536).default(256),
|
|
7172
|
+
durationMs: z6.number().int().min(0).max(36e5).default(0),
|
|
7173
|
+
cols: z6.number().int().min(1).max(1e3).default(120),
|
|
7174
|
+
rows: z6.number().int().min(1).max(1e3).default(30)
|
|
8091
7175
|
})).mutation(async ({ input }) => {
|
|
8092
7176
|
const agentId = input.agentId ?? agentManager.getDefaultAgentId();
|
|
8093
7177
|
if (!agentId) throw new TRPCError4({ code: "PRECONDITION_FAILED", message: "No agent available" });
|
|
@@ -8134,9 +7218,9 @@ Context:
|
|
|
8134
7218
|
return { spawnId: res.spawnId, agentId, stressSessionId };
|
|
8135
7219
|
}),
|
|
8136
7220
|
/** Kill a PTY session. */
|
|
8137
|
-
kill: protectedProcedure.input(
|
|
8138
|
-
agentId:
|
|
8139
|
-
spawnId:
|
|
7221
|
+
kill: protectedProcedure.input(z6.object({
|
|
7222
|
+
agentId: z6.string().max(128).optional(),
|
|
7223
|
+
spawnId: z6.string().max(128)
|
|
8140
7224
|
})).mutation(async ({ input }) => {
|
|
8141
7225
|
const agentId = input.agentId ?? agentManager.getDefaultAgentId();
|
|
8142
7226
|
if (!agentId) throw new TRPCError4({ code: "PRECONDITION_FAILED", message: "No agent available" });
|
|
@@ -8154,7 +7238,9 @@ export {
|
|
|
8154
7238
|
router,
|
|
8155
7239
|
publicProcedure,
|
|
8156
7240
|
protectedProcedure,
|
|
7241
|
+
requireLoopback,
|
|
8157
7242
|
requireLoopbackOrToken,
|
|
7243
|
+
requireHuman,
|
|
8158
7244
|
requireServiceAction,
|
|
8159
7245
|
getAllowedServiceIds,
|
|
8160
7246
|
requireEnvAction,
|
|
@@ -8206,6 +7292,7 @@ export {
|
|
|
8206
7292
|
kanbanStore,
|
|
8207
7293
|
executeKanbanCommands,
|
|
8208
7294
|
executeKanbanBoardCommands,
|
|
7295
|
+
buildKanbanCardPrompt,
|
|
8209
7296
|
ClaudeCodeRunner,
|
|
8210
7297
|
shutdownCodexAppServer,
|
|
8211
7298
|
CodexRunner,
|
|
@@ -8215,4 +7302,4 @@ export {
|
|
|
8215
7302
|
startCliSession,
|
|
8216
7303
|
chatRouter
|
|
8217
7304
|
};
|
|
8218
|
-
//# sourceMappingURL=chunk-
|
|
7305
|
+
//# sourceMappingURL=chunk-SEPAURTQ.js.map
|