@docyrus/docyrus 0.0.31 → 0.0.33
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-loader.js +74 -40
- package/agent-loader.js.map +4 -4
- package/main.js +2 -2
- package/main.js.map +1 -1
- package/package.json +1 -1
- package/resources/pi-agent/extensions/docyrus-web-browser.ts +31 -0
- package/resources/pi-agent/shared/docyrusWebBrowserProtocol.ts +169 -0
- package/resources/pi-agent/skills/diffity-diff/SKILL.md +1 -1
- package/resources/pi-agent/skills/diffity-resolve/SKILL.md +4 -4
- package/resources/pi-agent/skills/diffity-review/SKILL.md +5 -4
- package/resources/pi-agent/skills/docyrus-api-dev/SKILL.md +36 -0
- package/resources/pi-agent/skills/docyrus-api-dev/references/acl-endpoints-frontend.md +295 -0
- package/resources/pi-agent/skills/docyrus-api-dev/references/authentication.md +4 -5
- package/resources/pi-agent/skills/docyrus-app-dev-react/SKILL.md +112 -85
- package/resources/pi-agent/skills/docyrus-app-dev-react/references/README.md +1 -0
- package/resources/pi-agent/skills/docyrus-app-dev-react/references/collections-and-patterns.md +1 -0
- package/resources/pi-agent/skills/docyrus-app-dev-react/references/component-selection-guide.md +27 -10
- package/server-loader.js +360 -94
- package/server-loader.js.map +4 -4
package/server-loader.js
CHANGED
|
@@ -690,9 +690,9 @@ var init_dist = __esm({
|
|
|
690
690
|
});
|
|
691
691
|
|
|
692
692
|
// src/server/server-loader.ts
|
|
693
|
-
var
|
|
693
|
+
var import_node_fs2 = require("node:fs");
|
|
694
694
|
var import_node_url = require("node:url");
|
|
695
|
-
var
|
|
695
|
+
var import_node_path7 = require("node:path");
|
|
696
696
|
var import_picocolors2 = __toESM(require_picocolors());
|
|
697
697
|
|
|
698
698
|
// src/agent/envStore.ts
|
|
@@ -793,11 +793,31 @@ var AgentEnvStore = class {
|
|
|
793
793
|
}
|
|
794
794
|
};
|
|
795
795
|
|
|
796
|
+
// src/agent/packagedExtensions.ts
|
|
797
|
+
var import_node_fs = require("node:fs");
|
|
798
|
+
var import_node_path2 = require("node:path");
|
|
799
|
+
var SERVER_ONLY_PACKAGED_EXTENSION_NAMES = /* @__PURE__ */ new Set(["docyrus-web-browser"]);
|
|
800
|
+
function isPackagedExtensionEntry(entryName, isDirectory) {
|
|
801
|
+
return isDirectory || entryName.endsWith(".ts") || entryName.endsWith(".js");
|
|
802
|
+
}
|
|
803
|
+
function getPackagedExtensionName(entryName) {
|
|
804
|
+
return entryName.replace(/\.(ts|js)$/u, "");
|
|
805
|
+
}
|
|
806
|
+
function resolvePackagedExtensionPaths(resourceRoot, runtime = "terminal") {
|
|
807
|
+
const extensionsRoot = (0, import_node_path2.join)(resourceRoot, "extensions");
|
|
808
|
+
if (!(0, import_node_fs.existsSync)(extensionsRoot)) {
|
|
809
|
+
return [];
|
|
810
|
+
}
|
|
811
|
+
return (0, import_node_fs.readdirSync)(extensionsRoot, {
|
|
812
|
+
withFileTypes: true
|
|
813
|
+
}).filter((entry) => isPackagedExtensionEntry(entry.name, entry.isDirectory())).filter((entry) => runtime === "server" || !SERVER_ONLY_PACKAGED_EXTENSION_NAMES.has(getPackagedExtensionName(entry.name))).map((entry) => (0, import_node_path2.join)(extensionsRoot, entry.name)).sort((left, right) => left.localeCompare(right));
|
|
814
|
+
}
|
|
815
|
+
|
|
796
816
|
// src/server/agentServer.ts
|
|
797
817
|
var import_node_child_process = require("node:child_process");
|
|
798
818
|
var import_node_crypto3 = require("node:crypto");
|
|
799
819
|
var import_promises5 = require("node:fs/promises");
|
|
800
|
-
var
|
|
820
|
+
var import_node_path6 = require("node:path");
|
|
801
821
|
|
|
802
822
|
// ../../node_modules/.pnpm/hono@4.12.8/node_modules/hono/dist/compose.js
|
|
803
823
|
var compose = (middleware, onError, onNotFound) => {
|
|
@@ -3105,9 +3125,122 @@ function parseAskUserResponseFromToolOutput(output) {
|
|
|
3105
3125
|
return normalizeAskUserResponse(output);
|
|
3106
3126
|
}
|
|
3107
3127
|
|
|
3128
|
+
// resources/pi-agent/shared/docyrusWebBrowserProtocol.ts
|
|
3129
|
+
var DOCYRUS_WEB_BROWSER_TAG = "docyrus_web_browser";
|
|
3130
|
+
var DOCYRUS_WEB_BROWSER_OPEN = `<${DOCYRUS_WEB_BROWSER_TAG}>`;
|
|
3131
|
+
var DOCYRUS_WEB_BROWSER_CLOSE = `</${DOCYRUS_WEB_BROWSER_TAG}>`;
|
|
3132
|
+
var DOCYRUS_WEB_BROWSER_RESULT_TAG = "docyrus_web_browser_result";
|
|
3133
|
+
var DOCYRUS_WEB_BROWSER_RESULT_OPEN = `<${DOCYRUS_WEB_BROWSER_RESULT_TAG}>`;
|
|
3134
|
+
var DOCYRUS_WEB_BROWSER_RESULT_CLOSE = `</${DOCYRUS_WEB_BROWSER_RESULT_TAG}>`;
|
|
3135
|
+
var WEB_PREVIEW_CONTEXT_TOOL = "web_preview_context";
|
|
3136
|
+
var WEB_PREVIEW_PLAYWRIGHT_TOOL = "web_preview_playwright";
|
|
3137
|
+
var DOCYRUS_WEB_BROWSER_TOOL_NAMES = [
|
|
3138
|
+
WEB_PREVIEW_CONTEXT_TOOL,
|
|
3139
|
+
WEB_PREVIEW_PLAYWRIGHT_TOOL
|
|
3140
|
+
];
|
|
3141
|
+
var DOCYRUS_WEB_BROWSER_CLIENT_TOOLS = [
|
|
3142
|
+
{
|
|
3143
|
+
name: WEB_PREVIEW_CONTEXT_TOOL,
|
|
3144
|
+
description: "Inspect the current Docyrus web preview state before automation. Prefer this first when preview availability or bridge state is unknown.",
|
|
3145
|
+
inputSchema: {
|
|
3146
|
+
type: "object",
|
|
3147
|
+
properties: {
|
|
3148
|
+
includeSnapshot: { type: "boolean" }
|
|
3149
|
+
},
|
|
3150
|
+
additionalProperties: false
|
|
3151
|
+
}
|
|
3152
|
+
},
|
|
3153
|
+
{
|
|
3154
|
+
name: WEB_PREVIEW_PLAYWRIGHT_TOOL,
|
|
3155
|
+
description: "Run Playwright-style actions against the Docyrus web preview. Prefer structured steps over raw scripts.",
|
|
3156
|
+
inputSchema: {
|
|
3157
|
+
type: "object",
|
|
3158
|
+
properties: {
|
|
3159
|
+
script: { type: "string" },
|
|
3160
|
+
steps: {
|
|
3161
|
+
type: "array",
|
|
3162
|
+
items: {
|
|
3163
|
+
type: "object",
|
|
3164
|
+
properties: {
|
|
3165
|
+
action: { type: "string" },
|
|
3166
|
+
selector: { type: "string" },
|
|
3167
|
+
url: { type: "string" },
|
|
3168
|
+
value: { type: "string" },
|
|
3169
|
+
values: {
|
|
3170
|
+
type: "array",
|
|
3171
|
+
items: { type: "string" }
|
|
3172
|
+
},
|
|
3173
|
+
key: { type: "string" },
|
|
3174
|
+
attribute: { type: "string" },
|
|
3175
|
+
timeoutMs: { type: "number" },
|
|
3176
|
+
state: { type: "string" }
|
|
3177
|
+
},
|
|
3178
|
+
additionalProperties: true
|
|
3179
|
+
}
|
|
3180
|
+
},
|
|
3181
|
+
timeoutMs: { type: "number" },
|
|
3182
|
+
stopOnError: { type: "boolean" }
|
|
3183
|
+
},
|
|
3184
|
+
additionalProperties: true
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
];
|
|
3188
|
+
function hashString2(value) {
|
|
3189
|
+
let hash = 0;
|
|
3190
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
3191
|
+
hash = (hash << 5) - hash + value.charCodeAt(index);
|
|
3192
|
+
hash |= 0;
|
|
3193
|
+
}
|
|
3194
|
+
return Math.abs(hash).toString(36);
|
|
3195
|
+
}
|
|
3196
|
+
function isRecord2(value) {
|
|
3197
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3198
|
+
}
|
|
3199
|
+
function isDocyrusWebBrowserToolName(value) {
|
|
3200
|
+
return DOCYRUS_WEB_BROWSER_TOOL_NAMES.some((toolName) => toolName === value);
|
|
3201
|
+
}
|
|
3202
|
+
function normalizeDocyrusWebBrowserToolRequest(value) {
|
|
3203
|
+
if (!isRecord2(value) || !isDocyrusWebBrowserToolName(value.tool)) {
|
|
3204
|
+
return void 0;
|
|
3205
|
+
}
|
|
3206
|
+
return {
|
|
3207
|
+
tool: value.tool,
|
|
3208
|
+
input: isRecord2(value.input) ? value.input : void 0
|
|
3209
|
+
};
|
|
3210
|
+
}
|
|
3211
|
+
function createDocyrusWebBrowserToolCallId(request) {
|
|
3212
|
+
return `docyrus_web_browser_${hashString2(JSON.stringify(request))}`;
|
|
3213
|
+
}
|
|
3214
|
+
function parseDocyrusWebBrowserRequestFromText(text) {
|
|
3215
|
+
const trimmed = text.trim();
|
|
3216
|
+
if (!trimmed.startsWith(DOCYRUS_WEB_BROWSER_OPEN) || !trimmed.endsWith(DOCYRUS_WEB_BROWSER_CLOSE)) {
|
|
3217
|
+
return void 0;
|
|
3218
|
+
}
|
|
3219
|
+
const body = trimmed.slice(DOCYRUS_WEB_BROWSER_OPEN.length, trimmed.length - DOCYRUS_WEB_BROWSER_CLOSE.length).trim();
|
|
3220
|
+
if (!body) {
|
|
3221
|
+
return void 0;
|
|
3222
|
+
}
|
|
3223
|
+
try {
|
|
3224
|
+
return normalizeDocyrusWebBrowserToolRequest(JSON.parse(body));
|
|
3225
|
+
} catch {
|
|
3226
|
+
return void 0;
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3229
|
+
function formatDocyrusWebBrowserToolResponsePrompt(response) {
|
|
3230
|
+
return [
|
|
3231
|
+
"The docyrus-web-browser client tool returned a result.",
|
|
3232
|
+
"",
|
|
3233
|
+
`${DOCYRUS_WEB_BROWSER_RESULT_OPEN}`,
|
|
3234
|
+
JSON.stringify(response, null, 2),
|
|
3235
|
+
`${DOCYRUS_WEB_BROWSER_RESULT_CLOSE}`,
|
|
3236
|
+
"",
|
|
3237
|
+
"Continue the task using this result. If the tool reported an availability or bridge blocker, explain that blocker exactly and do not claim success."
|
|
3238
|
+
].join("\n");
|
|
3239
|
+
}
|
|
3240
|
+
|
|
3108
3241
|
// src/server/eventBridge.ts
|
|
3109
3242
|
function createEventBridge(params) {
|
|
3110
|
-
const { messageId, onChunk, onDone, onError, onAskUser } = params;
|
|
3243
|
+
const { messageId, onChunk, onDone, onError, onAskUser, onDocyrusWebBrowserTool } = params;
|
|
3111
3244
|
const activeToolCalls = /* @__PURE__ */ new Map();
|
|
3112
3245
|
let activeTextBuffer = null;
|
|
3113
3246
|
function flushBufferedTextToStream(close) {
|
|
@@ -3143,6 +3276,27 @@ function createEventBridge(params) {
|
|
|
3143
3276
|
});
|
|
3144
3277
|
return true;
|
|
3145
3278
|
}
|
|
3279
|
+
function maybeEmitDocyrusWebBrowserTool(text) {
|
|
3280
|
+
const request = parseDocyrusWebBrowserRequestFromText(text);
|
|
3281
|
+
if (!request) {
|
|
3282
|
+
return false;
|
|
3283
|
+
}
|
|
3284
|
+
const toolCallId = createDocyrusWebBrowserToolCallId(request);
|
|
3285
|
+
onDocyrusWebBrowserTool?.({ toolCallId, request });
|
|
3286
|
+
onChunk({ type: "tool-input-start", toolCallId, toolName: request.tool, dynamic: true });
|
|
3287
|
+
onChunk({
|
|
3288
|
+
type: "tool-input-available",
|
|
3289
|
+
toolCallId,
|
|
3290
|
+
toolName: request.tool,
|
|
3291
|
+
input: request.input ?? {},
|
|
3292
|
+
dynamic: true
|
|
3293
|
+
});
|
|
3294
|
+
return true;
|
|
3295
|
+
}
|
|
3296
|
+
function shouldKeepBufferingDynamicToolText(text) {
|
|
3297
|
+
const dynamicToolTags = ["<ask_user>", "<docyrus_web_browser>"];
|
|
3298
|
+
return dynamicToolTags.some((tag) => tag.startsWith(text) || text.startsWith(tag));
|
|
3299
|
+
}
|
|
3146
3300
|
function handleEvent(event) {
|
|
3147
3301
|
switch (event.type) {
|
|
3148
3302
|
case "message_update": {
|
|
@@ -3181,7 +3335,7 @@ function createEventBridge(params) {
|
|
|
3181
3335
|
break;
|
|
3182
3336
|
}
|
|
3183
3337
|
activeTextBuffer.text += assistantEvent.delta ?? "";
|
|
3184
|
-
if (
|
|
3338
|
+
if (shouldKeepBufferingDynamicToolText(activeTextBuffer.text)) {
|
|
3185
3339
|
break;
|
|
3186
3340
|
}
|
|
3187
3341
|
flushBufferedTextToStream(false);
|
|
@@ -3197,7 +3351,7 @@ function createEventBridge(params) {
|
|
|
3197
3351
|
activeTextBuffer = null;
|
|
3198
3352
|
break;
|
|
3199
3353
|
}
|
|
3200
|
-
if (!maybeEmitAskUser(activeTextBuffer.text)) {
|
|
3354
|
+
if (!maybeEmitAskUser(activeTextBuffer.text) && !maybeEmitDocyrusWebBrowserTool(activeTextBuffer.text)) {
|
|
3201
3355
|
flushBufferedTextToStream(true);
|
|
3202
3356
|
} else {
|
|
3203
3357
|
activeTextBuffer = null;
|
|
@@ -3282,7 +3436,7 @@ function createEventBridge(params) {
|
|
|
3282
3436
|
|
|
3283
3437
|
// src/agent/modelsConfig.ts
|
|
3284
3438
|
var import_promises2 = require("node:fs/promises");
|
|
3285
|
-
var
|
|
3439
|
+
var import_node_path3 = require("node:path");
|
|
3286
3440
|
function createDefaultState2() {
|
|
3287
3441
|
return {
|
|
3288
3442
|
providers: {}
|
|
@@ -3306,7 +3460,7 @@ async function readModelsConfig(filePath) {
|
|
|
3306
3460
|
}
|
|
3307
3461
|
}
|
|
3308
3462
|
async function writeModelsConfig(filePath, state) {
|
|
3309
|
-
const directory = (0,
|
|
3463
|
+
const directory = (0, import_node_path3.dirname)(filePath);
|
|
3310
3464
|
await (0, import_promises2.mkdir)(directory, {
|
|
3311
3465
|
recursive: true,
|
|
3312
3466
|
mode: 448
|
|
@@ -3361,7 +3515,7 @@ function createCustomOpenAiProviderConfig(params) {
|
|
|
3361
3515
|
function createAzureProviderConfig(params) {
|
|
3362
3516
|
const providerConfig = {
|
|
3363
3517
|
baseUrl: params.baseUrl,
|
|
3364
|
-
apiKey: "
|
|
3518
|
+
apiKey: "AZURE_OPENAI_API_KEY"
|
|
3365
3519
|
};
|
|
3366
3520
|
if (params.useCustomModel) {
|
|
3367
3521
|
providerConfig.api = "azure-openai-responses";
|
|
@@ -3390,6 +3544,22 @@ function trimOrUndefined(value) {
|
|
|
3390
3544
|
const trimmed = value?.trim();
|
|
3391
3545
|
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
3392
3546
|
}
|
|
3547
|
+
function normalizeAzureBaseUrl(baseUrl) {
|
|
3548
|
+
const trimmed = baseUrl.trim().replace(/\/+$/, "");
|
|
3549
|
+
try {
|
|
3550
|
+
const url = new URL(trimmed);
|
|
3551
|
+
url.search = "";
|
|
3552
|
+
url.hash = "";
|
|
3553
|
+
if (url.pathname.endsWith("/openai/v1")) {
|
|
3554
|
+
url.pathname = url.pathname.slice(0, -3);
|
|
3555
|
+
} else if (url.pathname.endsWith("/openai/responses")) {
|
|
3556
|
+
url.pathname = url.pathname.slice(0, -10);
|
|
3557
|
+
}
|
|
3558
|
+
return url.toString().replace(/\/+$/, "");
|
|
3559
|
+
} catch {
|
|
3560
|
+
return trimmed.replace(/\/openai\/v1$/i, "/openai").replace(/\/openai\/responses$/i, "/openai");
|
|
3561
|
+
}
|
|
3562
|
+
}
|
|
3393
3563
|
async function saveGenericApiKey(params) {
|
|
3394
3564
|
params.authStorage.set(params.providerId, {
|
|
3395
3565
|
type: "api_key",
|
|
@@ -3416,6 +3586,7 @@ async function saveCustomOpenAiConfig(params) {
|
|
|
3416
3586
|
async function saveAzureConfig(params) {
|
|
3417
3587
|
const modelId = params.modelId.trim();
|
|
3418
3588
|
const useCustomModel = params.useCustomModel ?? false;
|
|
3589
|
+
const normalizedBaseUrl = normalizeAzureBaseUrl(params.baseUrl);
|
|
3419
3590
|
params.authStorage.set("azure-openai-responses", {
|
|
3420
3591
|
type: "api_key",
|
|
3421
3592
|
key: params.apiKey.trim()
|
|
@@ -3440,7 +3611,7 @@ async function saveAzureConfig(params) {
|
|
|
3440
3611
|
}
|
|
3441
3612
|
await params.envStore.setMany(envValues);
|
|
3442
3613
|
await upsertModelsProvider(params.modelsJsonPath, "azure-openai-responses", createAzureProviderConfig({
|
|
3443
|
-
baseUrl:
|
|
3614
|
+
baseUrl: normalizedBaseUrl,
|
|
3444
3615
|
modelId,
|
|
3445
3616
|
useCustomModel
|
|
3446
3617
|
}));
|
|
@@ -3687,7 +3858,7 @@ function getProviderFormFields(params) {
|
|
|
3687
3858
|
title: "Azure OpenAI base URL",
|
|
3688
3859
|
required: true,
|
|
3689
3860
|
component: "text",
|
|
3690
|
-
placeholder: "https://my-resource.openai.azure.com/openai
|
|
3861
|
+
placeholder: "https://my-resource.openai.azure.com/openai",
|
|
3691
3862
|
dependsOn: { field: "configMode", equals: "base-url" }
|
|
3692
3863
|
},
|
|
3693
3864
|
{
|
|
@@ -3716,8 +3887,8 @@ function getProviderFormFields(params) {
|
|
|
3716
3887
|
name: "apiVersion",
|
|
3717
3888
|
title: "API version",
|
|
3718
3889
|
component: "text",
|
|
3719
|
-
defaultValue: "2025-
|
|
3720
|
-
placeholder: "2025-
|
|
3890
|
+
defaultValue: "2025-04-01-preview",
|
|
3891
|
+
placeholder: "2025-04-01-preview"
|
|
3721
3892
|
}
|
|
3722
3893
|
];
|
|
3723
3894
|
case "amazon-bedrock":
|
|
@@ -3909,7 +4080,7 @@ async function applyProviderLogin(params) {
|
|
|
3909
4080
|
return { providerId: provider.id, preferredModelId: params.input.modelId };
|
|
3910
4081
|
}
|
|
3911
4082
|
case "azure-openai-responses": {
|
|
3912
|
-
const baseUrl = params.input.baseUrl ?? (params.input.resourceName ? `https://${params.input.resourceName}.openai.azure.com/openai
|
|
4083
|
+
const baseUrl = params.input.baseUrl ?? (params.input.resourceName ? `https://${params.input.resourceName}.openai.azure.com/openai` : void 0);
|
|
3913
4084
|
if (!baseUrl) {
|
|
3914
4085
|
throw new Error("Azure login requires either baseUrl or resourceName.");
|
|
3915
4086
|
}
|
|
@@ -3949,9 +4120,14 @@ async function applyProviderLogin(params) {
|
|
|
3949
4120
|
}
|
|
3950
4121
|
}
|
|
3951
4122
|
async function refreshSessionAfterCredentialChange(params) {
|
|
4123
|
+
await params.envStore?.hydrateProcessEnv(process.env);
|
|
3952
4124
|
params.modelRegistry.refresh();
|
|
3953
4125
|
const availableModels = params.modelRegistry.getAvailable();
|
|
3954
4126
|
const preferredModel = params.preferredProviderId && params.preferredModelId ? availableModels.find((model) => model.provider === params.preferredProviderId && model.id === params.preferredModelId) : params.preferredProviderId ? availableModels.find((model) => model.provider === params.preferredProviderId) : void 0;
|
|
4127
|
+
if (preferredModel) {
|
|
4128
|
+
await params.session.setModel(preferredModel);
|
|
4129
|
+
return;
|
|
4130
|
+
}
|
|
3955
4131
|
const currentModel = params.session.model;
|
|
3956
4132
|
const currentModelStillAvailable = currentModel ? availableModels.some((model) => model.provider === currentModel.provider && model.id === currentModel.id) : false;
|
|
3957
4133
|
if (currentModel && !currentModelStillAvailable) {
|
|
@@ -4132,21 +4308,21 @@ var OAuthFlowManager = class {
|
|
|
4132
4308
|
var import_node_crypto2 = require("node:crypto");
|
|
4133
4309
|
var import_promises3 = require("node:fs/promises");
|
|
4134
4310
|
var import_node_os = require("node:os");
|
|
4135
|
-
var
|
|
4311
|
+
var import_node_path4 = require("node:path");
|
|
4136
4312
|
var PROJECT_CONFIG_NAME = ".pi/mcp.json";
|
|
4137
4313
|
var IMPORT_PATHS = {
|
|
4138
|
-
"cursor": (0,
|
|
4139
|
-
"claude-code": (0,
|
|
4140
|
-
"claude-desktop": (0,
|
|
4141
|
-
"codex": (0,
|
|
4142
|
-
"windsurf": (0,
|
|
4314
|
+
"cursor": (0, import_node_path4.join)((0, import_node_os.homedir)(), ".cursor", "mcp.json"),
|
|
4315
|
+
"claude-code": (0, import_node_path4.join)((0, import_node_os.homedir)(), ".claude", "claude_desktop_config.json"),
|
|
4316
|
+
"claude-desktop": (0, import_node_path4.join)((0, import_node_os.homedir)(), "Library", "Application Support", "Claude", "claude_desktop_config.json"),
|
|
4317
|
+
"codex": (0, import_node_path4.join)((0, import_node_os.homedir)(), ".codex", "config.json"),
|
|
4318
|
+
"windsurf": (0, import_node_path4.join)((0, import_node_os.homedir)(), ".windsurf", "mcp.json"),
|
|
4143
4319
|
"vscode": ".vscode/mcp.json"
|
|
4144
4320
|
};
|
|
4145
4321
|
function getMcpConfigPath(agentDir) {
|
|
4146
|
-
return (0,
|
|
4322
|
+
return (0, import_node_path4.join)(agentDir, "mcp.json");
|
|
4147
4323
|
}
|
|
4148
4324
|
function getMcpCachePath(agentDir) {
|
|
4149
|
-
return (0,
|
|
4325
|
+
return (0, import_node_path4.join)(agentDir, "mcp-cache.json");
|
|
4150
4326
|
}
|
|
4151
4327
|
var SERVER_NAME_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;
|
|
4152
4328
|
function validateServerName(name) {
|
|
@@ -4283,7 +4459,7 @@ async function loadMcpServerConfig(agentDir, cwd) {
|
|
|
4283
4459
|
if (!importPath) {
|
|
4284
4460
|
continue;
|
|
4285
4461
|
}
|
|
4286
|
-
const fullPath = importPath.startsWith(".") ? (0,
|
|
4462
|
+
const fullPath = importPath.startsWith(".") ? (0, import_node_path4.resolve)(cwd, importPath) : importPath;
|
|
4287
4463
|
const imported = await readJsonFile(fullPath);
|
|
4288
4464
|
if (!imported) {
|
|
4289
4465
|
continue;
|
|
@@ -4296,7 +4472,7 @@ async function loadMcpServerConfig(agentDir, cwd) {
|
|
|
4296
4472
|
}
|
|
4297
4473
|
}
|
|
4298
4474
|
}
|
|
4299
|
-
const projectPath = (0,
|
|
4475
|
+
const projectPath = (0, import_node_path4.resolve)(cwd, PROJECT_CONFIG_NAME);
|
|
4300
4476
|
if (projectPath !== configPath) {
|
|
4301
4477
|
const projectRaw = await readJsonFile(projectPath);
|
|
4302
4478
|
if (projectRaw) {
|
|
@@ -4380,7 +4556,7 @@ async function getServerProvenance(agentDir, cwd) {
|
|
|
4380
4556
|
if (!importPath) {
|
|
4381
4557
|
continue;
|
|
4382
4558
|
}
|
|
4383
|
-
const fullPath = importPath.startsWith(".") ? (0,
|
|
4559
|
+
const fullPath = importPath.startsWith(".") ? (0, import_node_path4.resolve)(cwd, importPath) : importPath;
|
|
4384
4560
|
const imported = await readJsonFile(fullPath);
|
|
4385
4561
|
if (!imported) {
|
|
4386
4562
|
continue;
|
|
@@ -4393,7 +4569,7 @@ async function getServerProvenance(agentDir, cwd) {
|
|
|
4393
4569
|
}
|
|
4394
4570
|
}
|
|
4395
4571
|
}
|
|
4396
|
-
const projectPath = (0,
|
|
4572
|
+
const projectPath = (0, import_node_path4.resolve)(cwd, PROJECT_CONFIG_NAME);
|
|
4397
4573
|
if (projectPath !== userPath) {
|
|
4398
4574
|
const projectRaw = await readJsonFile(projectPath);
|
|
4399
4575
|
if (projectRaw) {
|
|
@@ -4417,7 +4593,7 @@ async function readUserConfig(agentDir) {
|
|
|
4417
4593
|
}
|
|
4418
4594
|
async function writeUserConfig(agentDir, raw2) {
|
|
4419
4595
|
const configPath = getMcpConfigPath(agentDir);
|
|
4420
|
-
await (0, import_promises3.mkdir)((0,
|
|
4596
|
+
await (0, import_promises3.mkdir)((0, import_node_path4.dirname)(configPath), { recursive: true });
|
|
4421
4597
|
const tmpPath = `${configPath}.${process.pid}.tmp`;
|
|
4422
4598
|
await (0, import_promises3.writeFile)(tmpPath, JSON.stringify(raw2, null, 2) + "\n", "utf-8");
|
|
4423
4599
|
await (0, import_promises3.rename)(tmpPath, configPath);
|
|
@@ -4475,7 +4651,7 @@ function formatToolName(toolName, serverName, prefix) {
|
|
|
4475
4651
|
|
|
4476
4652
|
// src/server/skillsService.ts
|
|
4477
4653
|
var import_promises4 = require("node:fs/promises");
|
|
4478
|
-
var
|
|
4654
|
+
var import_node_path5 = require("node:path");
|
|
4479
4655
|
function parseFrontmatter(content) {
|
|
4480
4656
|
const frontmatter = {};
|
|
4481
4657
|
if (!content.startsWith("---")) {
|
|
@@ -4509,7 +4685,7 @@ async function dirExists(path) {
|
|
|
4509
4685
|
}
|
|
4510
4686
|
}
|
|
4511
4687
|
async function listSkills(agentDir) {
|
|
4512
|
-
const skillsDir = (0,
|
|
4688
|
+
const skillsDir = (0, import_node_path5.join)(agentDir, "skills");
|
|
4513
4689
|
let entries;
|
|
4514
4690
|
try {
|
|
4515
4691
|
entries = await (0, import_promises4.readdir)(skillsDir, { withFileTypes: true });
|
|
@@ -4521,8 +4697,8 @@ async function listSkills(agentDir) {
|
|
|
4521
4697
|
if (!entry.isDirectory()) {
|
|
4522
4698
|
continue;
|
|
4523
4699
|
}
|
|
4524
|
-
const skillDir = (0,
|
|
4525
|
-
const skillMdPath = (0,
|
|
4700
|
+
const skillDir = (0, import_node_path5.join)(skillsDir, entry.name);
|
|
4701
|
+
const skillMdPath = (0, import_node_path5.join)(skillDir, "SKILL.md");
|
|
4526
4702
|
let content;
|
|
4527
4703
|
try {
|
|
4528
4704
|
content = await (0, import_promises4.readFile)(skillMdPath, "utf-8");
|
|
@@ -4530,7 +4706,7 @@ async function listSkills(agentDir) {
|
|
|
4530
4706
|
continue;
|
|
4531
4707
|
}
|
|
4532
4708
|
const parsed = parseFrontmatter(content);
|
|
4533
|
-
const hasReferences = await dirExists((0,
|
|
4709
|
+
const hasReferences = await dirExists((0, import_node_path5.join)(skillDir, "references"));
|
|
4534
4710
|
skills.push({
|
|
4535
4711
|
name: parsed.frontmatter.name || entry.name,
|
|
4536
4712
|
description: parsed.frontmatter.description || null,
|
|
@@ -4543,7 +4719,7 @@ async function listSkills(agentDir) {
|
|
|
4543
4719
|
return skills.sort((a, b) => a.name.localeCompare(b.name));
|
|
4544
4720
|
}
|
|
4545
4721
|
async function getSkillDetail(agentDir, skillName) {
|
|
4546
|
-
const skillsDir = (0,
|
|
4722
|
+
const skillsDir = (0, import_node_path5.join)(agentDir, "skills");
|
|
4547
4723
|
let entries;
|
|
4548
4724
|
try {
|
|
4549
4725
|
entries = await (0, import_promises4.readdir)(skillsDir, { withFileTypes: true });
|
|
@@ -4554,8 +4730,8 @@ async function getSkillDetail(agentDir, skillName) {
|
|
|
4554
4730
|
if (!entry.isDirectory()) {
|
|
4555
4731
|
continue;
|
|
4556
4732
|
}
|
|
4557
|
-
const skillDir = (0,
|
|
4558
|
-
const skillMdPath = (0,
|
|
4733
|
+
const skillDir = (0, import_node_path5.join)(skillsDir, entry.name);
|
|
4734
|
+
const skillMdPath = (0, import_node_path5.join)(skillDir, "SKILL.md");
|
|
4559
4735
|
let content;
|
|
4560
4736
|
try {
|
|
4561
4737
|
content = await (0, import_promises4.readFile)(skillMdPath, "utf-8");
|
|
@@ -4565,7 +4741,7 @@ async function getSkillDetail(agentDir, skillName) {
|
|
|
4565
4741
|
const parsed = parseFrontmatter(content);
|
|
4566
4742
|
const fmName = parsed.frontmatter.name || entry.name;
|
|
4567
4743
|
if (entry.name === skillName || fmName === skillName) {
|
|
4568
|
-
const hasReferences = await dirExists((0,
|
|
4744
|
+
const hasReferences = await dirExists((0, import_node_path5.join)(skillDir, "references"));
|
|
4569
4745
|
return {
|
|
4570
4746
|
skill: {
|
|
4571
4747
|
name: fmName,
|
|
@@ -4602,7 +4778,7 @@ var BUILT_IN_TOOLS = {
|
|
|
4602
4778
|
]
|
|
4603
4779
|
};
|
|
4604
4780
|
async function listAllTools(params) {
|
|
4605
|
-
const { profile, agentDir, cwd } = params;
|
|
4781
|
+
const { profile, agentDir, cwd, includeDocyrusWebBrowser } = params;
|
|
4606
4782
|
const tools = [];
|
|
4607
4783
|
const builtIn = BUILT_IN_TOOLS[profile] ?? BUILT_IN_TOOLS.coder;
|
|
4608
4784
|
for (const tool of builtIn) {
|
|
@@ -4612,6 +4788,16 @@ async function listAllTools(params) {
|
|
|
4612
4788
|
source: "built-in"
|
|
4613
4789
|
});
|
|
4614
4790
|
}
|
|
4791
|
+
if (includeDocyrusWebBrowser) {
|
|
4792
|
+
for (const tool of DOCYRUS_WEB_BROWSER_CLIENT_TOOLS) {
|
|
4793
|
+
tools.push({
|
|
4794
|
+
name: tool.name,
|
|
4795
|
+
description: tool.description,
|
|
4796
|
+
source: "built-in",
|
|
4797
|
+
inputSchema: tool.inputSchema
|
|
4798
|
+
});
|
|
4799
|
+
}
|
|
4800
|
+
}
|
|
4615
4801
|
let config;
|
|
4616
4802
|
let cache;
|
|
4617
4803
|
try {
|
|
@@ -4661,6 +4847,13 @@ async function listAllTools(params) {
|
|
|
4661
4847
|
function generateMessageId() {
|
|
4662
4848
|
return `msg_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
4663
4849
|
}
|
|
4850
|
+
function getLastAssistantMessage(messages) {
|
|
4851
|
+
if (messages.length === 0) {
|
|
4852
|
+
return void 0;
|
|
4853
|
+
}
|
|
4854
|
+
const lastMessage = messages[messages.length - 1];
|
|
4855
|
+
return lastMessage.role === "assistant" ? lastMessage : void 0;
|
|
4856
|
+
}
|
|
4664
4857
|
function extractLastUserText(messages) {
|
|
4665
4858
|
if (messages.length === 0) {
|
|
4666
4859
|
return void 0;
|
|
@@ -4677,21 +4870,58 @@ function extractLastUserText(messages) {
|
|
|
4677
4870
|
return void 0;
|
|
4678
4871
|
}
|
|
4679
4872
|
function extractAskUserToolResponse(messages) {
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4873
|
+
const message = getLastAssistantMessage(messages);
|
|
4874
|
+
if (!message) {
|
|
4875
|
+
return void 0;
|
|
4876
|
+
}
|
|
4877
|
+
for (let partIndex = message.parts.length - 1; partIndex >= 0; partIndex -= 1) {
|
|
4878
|
+
const part = message.parts[partIndex];
|
|
4879
|
+
if (part.type === "dynamic-tool" && part.toolName === "ask_user" && part.state === "output-available" && typeof part.toolCallId === "string") {
|
|
4880
|
+
const response = parseAskUserResponseFromToolOutput(part.output);
|
|
4881
|
+
if (response) {
|
|
4882
|
+
return {
|
|
4883
|
+
toolCallId: part.toolCallId,
|
|
4884
|
+
response
|
|
4885
|
+
};
|
|
4886
|
+
}
|
|
4684
4887
|
}
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4888
|
+
}
|
|
4889
|
+
return void 0;
|
|
4890
|
+
}
|
|
4891
|
+
function extractDocyrusWebBrowserToolResponse(messages) {
|
|
4892
|
+
const message = getLastAssistantMessage(messages);
|
|
4893
|
+
if (!message) {
|
|
4894
|
+
return void 0;
|
|
4895
|
+
}
|
|
4896
|
+
for (let partIndex = message.parts.length - 1; partIndex >= 0; partIndex -= 1) {
|
|
4897
|
+
const part = message.parts[partIndex];
|
|
4898
|
+
if (part.type === "dynamic-tool" && isDocyrusWebBrowserToolName(part.toolName) && typeof part.toolCallId === "string" && (part.state === "output-available" || part.state === "output-error")) {
|
|
4899
|
+
const errorText = typeof part.errorText === "string" ? part.errorText : typeof part.output === "string" && part.state === "output-error" ? part.output : void 0;
|
|
4900
|
+
return {
|
|
4901
|
+
toolCallId: part.toolCallId,
|
|
4902
|
+
toolName: part.toolName,
|
|
4903
|
+
output: part.state === "output-available" ? part.output : void 0,
|
|
4904
|
+
errorText,
|
|
4905
|
+
isError: part.state === "output-error"
|
|
4906
|
+
};
|
|
4907
|
+
}
|
|
4908
|
+
}
|
|
4909
|
+
return void 0;
|
|
4910
|
+
}
|
|
4911
|
+
function extractDocyrusWebBrowserToolRequest(messages, toolCallId) {
|
|
4912
|
+
const message = getLastAssistantMessage(messages);
|
|
4913
|
+
if (!message) {
|
|
4914
|
+
return void 0;
|
|
4915
|
+
}
|
|
4916
|
+
for (let partIndex = message.parts.length - 1; partIndex >= 0; partIndex -= 1) {
|
|
4917
|
+
const part = message.parts[partIndex];
|
|
4918
|
+
if (part.type === "dynamic-tool" && isDocyrusWebBrowserToolName(part.toolName) && part.toolCallId === toolCallId) {
|
|
4919
|
+
const request = normalizeDocyrusWebBrowserToolRequest({
|
|
4920
|
+
tool: part.toolName,
|
|
4921
|
+
input: part.input
|
|
4922
|
+
});
|
|
4923
|
+
if (request) {
|
|
4924
|
+
return request;
|
|
4695
4925
|
}
|
|
4696
4926
|
}
|
|
4697
4927
|
}
|
|
@@ -4797,6 +5027,17 @@ function convertSessionEntriesToUIMessages(entries) {
|
|
|
4797
5027
|
});
|
|
4798
5028
|
continue;
|
|
4799
5029
|
}
|
|
5030
|
+
const docyrusWebBrowserRequest = parseDocyrusWebBrowserRequestFromText(block.text);
|
|
5031
|
+
if (docyrusWebBrowserRequest) {
|
|
5032
|
+
parts.push({
|
|
5033
|
+
type: "dynamic-tool",
|
|
5034
|
+
toolCallId: createDocyrusWebBrowserToolCallId(docyrusWebBrowserRequest),
|
|
5035
|
+
toolName: docyrusWebBrowserRequest.tool,
|
|
5036
|
+
state: "input-available",
|
|
5037
|
+
input: docyrusWebBrowserRequest.input ?? {}
|
|
5038
|
+
});
|
|
5039
|
+
continue;
|
|
5040
|
+
}
|
|
4800
5041
|
parts.push({ type: "text", text: block.text });
|
|
4801
5042
|
} else if (block.type === "thinking" && typeof block.thinking === "string") {
|
|
4802
5043
|
parts.push({ type: "reasoning", text: block.thinking, state: "complete" });
|
|
@@ -4841,8 +5082,8 @@ var FS_IGNORE = /* @__PURE__ */ new Set([
|
|
|
4841
5082
|
".svelte-kit"
|
|
4842
5083
|
]);
|
|
4843
5084
|
function resolveSafePath(cwd, requestPath) {
|
|
4844
|
-
const resolved = (0,
|
|
4845
|
-
const normalizedCwd = cwd.endsWith(
|
|
5085
|
+
const resolved = (0, import_node_path6.resolve)(cwd, requestPath);
|
|
5086
|
+
const normalizedCwd = cwd.endsWith(import_node_path6.sep) ? cwd : cwd + import_node_path6.sep;
|
|
4846
5087
|
if (resolved !== cwd && !resolved.startsWith(normalizedCwd)) {
|
|
4847
5088
|
throw new Error("Path escapes working directory");
|
|
4848
5089
|
}
|
|
@@ -4879,8 +5120,8 @@ async function buildTree(params) {
|
|
|
4879
5120
|
if (ignore.has(entry.name)) {
|
|
4880
5121
|
continue;
|
|
4881
5122
|
}
|
|
4882
|
-
const fullPath = (0,
|
|
4883
|
-
const relativePath = (0,
|
|
5123
|
+
const fullPath = (0, import_node_path6.join)(dir, entry.name);
|
|
5124
|
+
const relativePath = (0, import_node_path6.relative)(cwd, fullPath);
|
|
4884
5125
|
if (entry.isDirectory()) {
|
|
4885
5126
|
const children = await buildTree({
|
|
4886
5127
|
dir: fullPath,
|
|
@@ -4917,8 +5158,8 @@ async function walkFiles(params) {
|
|
|
4917
5158
|
if (ignore.has(entry.name)) {
|
|
4918
5159
|
continue;
|
|
4919
5160
|
}
|
|
4920
|
-
const fullPath = (0,
|
|
4921
|
-
const relativePath = (0,
|
|
5161
|
+
const fullPath = (0, import_node_path6.join)(dir, entry.name);
|
|
5162
|
+
const relativePath = (0, import_node_path6.relative)(cwd, fullPath);
|
|
4922
5163
|
if (entry.isDirectory()) {
|
|
4923
5164
|
await walkFiles({ dir: fullPath, cwd, pattern, ignore, maxResults, results });
|
|
4924
5165
|
} else if (entry.isFile() && pattern.test(relativePath)) {
|
|
@@ -4930,6 +5171,7 @@ async function createAgentServer(params) {
|
|
|
4930
5171
|
const { port, sessionManager, modelRegistry, authRuntime, context, onCreateSession, onResumeSession, authToken } = params;
|
|
4931
5172
|
let activeSession = params.session;
|
|
4932
5173
|
const pendingAskUserRequests = /* @__PURE__ */ new Map();
|
|
5174
|
+
const pendingDocyrusWebBrowserRequests = /* @__PURE__ */ new Map();
|
|
4933
5175
|
const oauthFlowManager = new OAuthFlowManager();
|
|
4934
5176
|
const app = new Hono2();
|
|
4935
5177
|
function getModelIdsByProvider() {
|
|
@@ -4983,14 +5225,31 @@ async function createAgentServer(params) {
|
|
|
4983
5225
|
}
|
|
4984
5226
|
const sessionId = body.sessionId?.trim() || activeSession.id?.trim() || "active";
|
|
4985
5227
|
const askUserResponse = extractAskUserToolResponse(messages);
|
|
5228
|
+
const docyrusWebBrowserResponse = extractDocyrusWebBrowserToolResponse(messages);
|
|
4986
5229
|
const pendingAskUser = pendingAskUserRequests.get(sessionId);
|
|
4987
|
-
const
|
|
5230
|
+
const pendingDocyrusWebBrowser = pendingDocyrusWebBrowserRequests.get(sessionId);
|
|
5231
|
+
const pendingDocyrusWebBrowserRequest = docyrusWebBrowserResponse ? pendingDocyrusWebBrowser?.get(docyrusWebBrowserResponse.toolCallId) ?? extractDocyrusWebBrowserToolRequest(messages, docyrusWebBrowserResponse.toolCallId) : void 0;
|
|
5232
|
+
const userMessage = askUserResponse ? pendingAskUser && pendingAskUser.toolCallId === askUserResponse.toolCallId ? formatAskUserResponsePrompt(askUserResponse.response) : void 0 : docyrusWebBrowserResponse ? pendingDocyrusWebBrowserRequest ? formatDocyrusWebBrowserToolResponsePrompt({
|
|
5233
|
+
tool: docyrusWebBrowserResponse.toolName,
|
|
5234
|
+
request: pendingDocyrusWebBrowserRequest.input,
|
|
5235
|
+
status: docyrusWebBrowserResponse.isError ? "error" : "success",
|
|
5236
|
+
output: docyrusWebBrowserResponse.output,
|
|
5237
|
+
errorText: docyrusWebBrowserResponse.errorText
|
|
5238
|
+
}) : void 0 : extractLastUserText(messages);
|
|
4988
5239
|
if (!userMessage) {
|
|
4989
|
-
return c.json({
|
|
5240
|
+
return c.json({
|
|
5241
|
+
error: askUserResponse ? "No matching pending ask_user request found" : docyrusWebBrowserResponse ? "No matching pending docyrus-web-browser request found" : "No user message found"
|
|
5242
|
+
}, 400);
|
|
4990
5243
|
}
|
|
4991
5244
|
if (askUserResponse) {
|
|
4992
5245
|
pendingAskUserRequests.delete(sessionId);
|
|
4993
5246
|
}
|
|
5247
|
+
if (docyrusWebBrowserResponse && pendingDocyrusWebBrowser) {
|
|
5248
|
+
pendingDocyrusWebBrowser.delete(docyrusWebBrowserResponse.toolCallId);
|
|
5249
|
+
if (pendingDocyrusWebBrowser.size === 0) {
|
|
5250
|
+
pendingDocyrusWebBrowserRequests.delete(sessionId);
|
|
5251
|
+
}
|
|
5252
|
+
}
|
|
4994
5253
|
if (activeSession.isStreaming) {
|
|
4995
5254
|
await activeSession.abort();
|
|
4996
5255
|
await waitForIdle(activeSession);
|
|
@@ -5012,6 +5271,11 @@ async function createAgentServer(params) {
|
|
|
5012
5271
|
onAskUser: ({ toolCallId, request }) => {
|
|
5013
5272
|
pendingAskUserRequests.set(sessionId, { toolCallId, request });
|
|
5014
5273
|
},
|
|
5274
|
+
onDocyrusWebBrowserTool: ({ toolCallId, request }) => {
|
|
5275
|
+
const pendingForSession = pendingDocyrusWebBrowserRequests.get(sessionId) ?? /* @__PURE__ */ new Map();
|
|
5276
|
+
pendingForSession.set(toolCallId, request);
|
|
5277
|
+
pendingDocyrusWebBrowserRequests.set(sessionId, pendingForSession);
|
|
5278
|
+
},
|
|
5015
5279
|
onDone: () => {
|
|
5016
5280
|
writeChunk({ type: "finish-step" });
|
|
5017
5281
|
writeChunk({ type: "finish" });
|
|
@@ -5194,6 +5458,7 @@ async function createAgentServer(params) {
|
|
|
5194
5458
|
await refreshSessionAfterCredentialChange({
|
|
5195
5459
|
session: activeSession,
|
|
5196
5460
|
modelRegistry,
|
|
5461
|
+
envStore: authRuntime.envStore,
|
|
5197
5462
|
preferredProviderId: result.providerId,
|
|
5198
5463
|
preferredModelId: result.preferredModelId
|
|
5199
5464
|
});
|
|
@@ -5225,6 +5490,7 @@ async function createAgentServer(params) {
|
|
|
5225
5490
|
await refreshSessionAfterCredentialChange({
|
|
5226
5491
|
session: activeSession,
|
|
5227
5492
|
modelRegistry,
|
|
5493
|
+
envStore: authRuntime.envStore,
|
|
5228
5494
|
preferredProviderId: providerId
|
|
5229
5495
|
});
|
|
5230
5496
|
}
|
|
@@ -5256,7 +5522,8 @@ async function createAgentServer(params) {
|
|
|
5256
5522
|
modelRegistry.refresh();
|
|
5257
5523
|
await refreshSessionAfterCredentialChange({
|
|
5258
5524
|
session: activeSession,
|
|
5259
|
-
modelRegistry
|
|
5525
|
+
modelRegistry,
|
|
5526
|
+
envStore: authRuntime.envStore
|
|
5260
5527
|
});
|
|
5261
5528
|
return c.json({
|
|
5262
5529
|
ok: true,
|
|
@@ -5383,7 +5650,7 @@ async function createAgentServer(params) {
|
|
|
5383
5650
|
}
|
|
5384
5651
|
try {
|
|
5385
5652
|
const resolved = resolveSafePath(context.cwd, body.path);
|
|
5386
|
-
await (0, import_promises5.mkdir)((0,
|
|
5653
|
+
await (0, import_promises5.mkdir)((0, import_node_path6.join)(resolved, ".."), { recursive: true });
|
|
5387
5654
|
await (0, import_promises5.writeFile)(resolved, body.content, "utf-8");
|
|
5388
5655
|
const fileStat = await (0, import_promises5.stat)(resolved);
|
|
5389
5656
|
return c.json({ ok: true, path: body.path, size: fileStat.size });
|
|
@@ -5414,7 +5681,7 @@ async function createAgentServer(params) {
|
|
|
5414
5681
|
try {
|
|
5415
5682
|
const resolvedFrom = resolveSafePath(context.cwd, body.from);
|
|
5416
5683
|
const resolvedTo = resolveSafePath(context.cwd, body.to);
|
|
5417
|
-
await (0, import_promises5.mkdir)((0,
|
|
5684
|
+
await (0, import_promises5.mkdir)((0, import_node_path6.join)(resolvedTo, ".."), { recursive: true });
|
|
5418
5685
|
await (0, import_promises5.rename)(resolvedFrom, resolvedTo);
|
|
5419
5686
|
return c.json({ ok: true, from: body.from, to: body.to });
|
|
5420
5687
|
} catch (error) {
|
|
@@ -5443,7 +5710,7 @@ async function createAgentServer(params) {
|
|
|
5443
5710
|
}
|
|
5444
5711
|
});
|
|
5445
5712
|
const CLI_EXEC = process.env.DOCYRUS_CLI_EXECUTABLE || process.execPath;
|
|
5446
|
-
const CLI_ENTRY = process.env.DOCYRUS_CLI_ENTRY || (0,
|
|
5713
|
+
const CLI_ENTRY = process.env.DOCYRUS_CLI_ENTRY || (0, import_node_path6.resolve)(process.argv[1] ? (0, import_node_path6.join)(process.argv[1], "..") : __dirname, "main.js");
|
|
5447
5714
|
const CLI_SCOPE = process.env.DOCYRUS_CLI_SCOPE;
|
|
5448
5715
|
const CLI_TIMEOUT_MS = 3e4;
|
|
5449
5716
|
function runCliCommand(args) {
|
|
@@ -5493,7 +5760,7 @@ async function createAgentServer(params) {
|
|
|
5493
5760
|
}
|
|
5494
5761
|
async function detectDevPort(cwd) {
|
|
5495
5762
|
try {
|
|
5496
|
-
const pkg = JSON.parse(await (0, import_promises5.readFile)((0,
|
|
5763
|
+
const pkg = JSON.parse(await (0, import_promises5.readFile)((0, import_node_path6.join)(cwd, "package.json"), "utf-8"));
|
|
5497
5764
|
const devScript = pkg.scripts?.dev;
|
|
5498
5765
|
if (devScript) {
|
|
5499
5766
|
const portFlag = devScript.match(/--port\s+(\d+)/);
|
|
@@ -5509,7 +5776,7 @@ async function createAgentServer(params) {
|
|
|
5509
5776
|
}
|
|
5510
5777
|
for (const name of ["vite.config.ts", "vite.config.mts", "vite.config.js"]) {
|
|
5511
5778
|
try {
|
|
5512
|
-
const content = await (0, import_promises5.readFile)((0,
|
|
5779
|
+
const content = await (0, import_promises5.readFile)((0, import_node_path6.join)(cwd, name), "utf-8");
|
|
5513
5780
|
const portMatch = content.match(/port\s*:\s*(\d+)/);
|
|
5514
5781
|
if (portMatch) {
|
|
5515
5782
|
return Number(portMatch[1]);
|
|
@@ -5519,19 +5786,19 @@ async function createAgentServer(params) {
|
|
|
5519
5786
|
}
|
|
5520
5787
|
for (const name of ["next.config.ts", "next.config.mts", "next.config.js", "next.config.mjs"]) {
|
|
5521
5788
|
try {
|
|
5522
|
-
await (0, import_promises5.stat)((0,
|
|
5789
|
+
await (0, import_promises5.stat)((0, import_node_path6.join)(cwd, name));
|
|
5523
5790
|
return 3e3;
|
|
5524
5791
|
} catch {
|
|
5525
5792
|
}
|
|
5526
5793
|
}
|
|
5527
5794
|
try {
|
|
5528
|
-
await (0, import_promises5.stat)((0,
|
|
5795
|
+
await (0, import_promises5.stat)((0, import_node_path6.join)(cwd, "angular.json"));
|
|
5529
5796
|
return 4200;
|
|
5530
5797
|
} catch {
|
|
5531
5798
|
}
|
|
5532
5799
|
for (const name of ["nuxt.config.ts", "nuxt.config.js"]) {
|
|
5533
5800
|
try {
|
|
5534
|
-
await (0, import_promises5.stat)((0,
|
|
5801
|
+
await (0, import_promises5.stat)((0, import_node_path6.join)(cwd, name));
|
|
5535
5802
|
return 3e3;
|
|
5536
5803
|
} catch {
|
|
5537
5804
|
}
|
|
@@ -5561,14 +5828,14 @@ async function createAgentServer(params) {
|
|
|
5561
5828
|
} catch {
|
|
5562
5829
|
}
|
|
5563
5830
|
try {
|
|
5564
|
-
const pkg = JSON.parse(await (0, import_promises5.readFile)((0,
|
|
5831
|
+
const pkg = JSON.parse(await (0, import_promises5.readFile)((0, import_node_path6.join)(cwd, "package.json"), "utf-8"));
|
|
5565
5832
|
packageName = pkg.name ?? null;
|
|
5566
5833
|
packageVersion = pkg.version ?? null;
|
|
5567
5834
|
} catch {
|
|
5568
5835
|
}
|
|
5569
5836
|
cachedProjectInfo = {
|
|
5570
5837
|
path: cwd,
|
|
5571
|
-
folder: (0,
|
|
5838
|
+
folder: (0, import_node_path6.basename)(cwd),
|
|
5572
5839
|
repo,
|
|
5573
5840
|
packageName,
|
|
5574
5841
|
packageVersion
|
|
@@ -5779,7 +6046,7 @@ async function createAgentServer(params) {
|
|
|
5779
6046
|
}
|
|
5780
6047
|
if (entry.status !== "deleted") {
|
|
5781
6048
|
try {
|
|
5782
|
-
const resolved = (0,
|
|
6049
|
+
const resolved = (0, import_node_path6.resolve)(cwd, entry.path);
|
|
5783
6050
|
const buf = await (0, import_promises5.readFile)(resolved);
|
|
5784
6051
|
if (buf.subarray(0, 8192).includes(0)) {
|
|
5785
6052
|
return null;
|
|
@@ -5958,7 +6225,7 @@ async function createAgentServer(params) {
|
|
|
5958
6225
|
});
|
|
5959
6226
|
app.get("/api/skills", async (c) => {
|
|
5960
6227
|
try {
|
|
5961
|
-
const skills = await listSkills(context.agentDir);
|
|
6228
|
+
const skills = (await listSkills(context.agentDir)).filter((skill) => skill.name !== "docyrus-chrome-devtools-cli");
|
|
5962
6229
|
return c.json({ skills });
|
|
5963
6230
|
} catch (error) {
|
|
5964
6231
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -5968,6 +6235,9 @@ async function createAgentServer(params) {
|
|
|
5968
6235
|
app.get("/api/skills/:skillName", async (c) => {
|
|
5969
6236
|
const skillName = c.req.param("skillName");
|
|
5970
6237
|
try {
|
|
6238
|
+
if (skillName === "docyrus-chrome-devtools-cli") {
|
|
6239
|
+
return c.json({ error: `Skill "${skillName}" not found` }, 404);
|
|
6240
|
+
}
|
|
5971
6241
|
const result = await getSkillDetail(context.agentDir, skillName);
|
|
5972
6242
|
if (!result) {
|
|
5973
6243
|
return c.json({ error: `Skill "${skillName}" not found` }, 404);
|
|
@@ -5983,7 +6253,8 @@ async function createAgentServer(params) {
|
|
|
5983
6253
|
const tools = await listAllTools({
|
|
5984
6254
|
profile: context.profile,
|
|
5985
6255
|
agentDir: context.agentDir,
|
|
5986
|
-
cwd: context.cwd
|
|
6256
|
+
cwd: context.cwd,
|
|
6257
|
+
includeDocyrusWebBrowser: true
|
|
5987
6258
|
});
|
|
5988
6259
|
const builtInCount = tools.filter((t) => t.source === "built-in").length;
|
|
5989
6260
|
const mcpCount = tools.filter((t) => t.source !== "built-in").length;
|
|
@@ -6288,31 +6559,22 @@ function readLoaderRequest() {
|
|
|
6288
6559
|
}
|
|
6289
6560
|
async function loadPiExports() {
|
|
6290
6561
|
const piPackageDir = readRequiredEnv("PI_PACKAGE_DIR");
|
|
6291
|
-
const moduleUrl = (0, import_node_url.pathToFileURL)((0,
|
|
6562
|
+
const moduleUrl = (0, import_node_url.pathToFileURL)((0, import_node_path7.join)(piPackageDir, "dist", "index.js")).href;
|
|
6292
6563
|
return await import(moduleUrl);
|
|
6293
6564
|
}
|
|
6294
6565
|
function resolvePackagedPiResourceRoot() {
|
|
6295
6566
|
const candidates = [
|
|
6296
|
-
(0,
|
|
6297
|
-
(0,
|
|
6298
|
-
(0,
|
|
6299
|
-
(0,
|
|
6567
|
+
(0, import_node_path7.resolve)(process.cwd(), "apps/api-cli/resources/pi-agent"),
|
|
6568
|
+
(0, import_node_path7.resolve)(__dirname, "../resources/pi-agent"),
|
|
6569
|
+
(0, import_node_path7.resolve)(__dirname, "resources/pi-agent"),
|
|
6570
|
+
(0, import_node_path7.resolve)(process.cwd(), "dist/apps/api-cli/resources/pi-agent")
|
|
6300
6571
|
];
|
|
6301
|
-
const resolved = candidates.find((candidate) => (0,
|
|
6572
|
+
const resolved = candidates.find((candidate) => (0, import_node_fs2.existsSync)(candidate));
|
|
6302
6573
|
if (!resolved) {
|
|
6303
6574
|
throw new Error(`Unable to locate pi agent resources. Checked: ${candidates.join(", ")}`);
|
|
6304
6575
|
}
|
|
6305
6576
|
return resolved;
|
|
6306
6577
|
}
|
|
6307
|
-
function resolvePackagedExtensionPaths(resourceRoot) {
|
|
6308
|
-
const extensionsRoot = (0, import_node_path6.join)(resourceRoot, "extensions");
|
|
6309
|
-
if (!(0, import_node_fs.existsSync)(extensionsRoot)) {
|
|
6310
|
-
return [];
|
|
6311
|
-
}
|
|
6312
|
-
return (0, import_node_fs.readdirSync)(extensionsRoot, {
|
|
6313
|
-
withFileTypes: true
|
|
6314
|
-
}).filter((entry) => entry.isDirectory() || entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".js"))).map((entry) => (0, import_node_path6.join)(extensionsRoot, entry.name)).sort((left, right) => left.localeCompare(right));
|
|
6315
|
-
}
|
|
6316
6578
|
function setProcessArgValue(flag, value) {
|
|
6317
6579
|
const existingIndex = process.argv.indexOf(flag);
|
|
6318
6580
|
if (existingIndex >= 0) {
|
|
@@ -6424,17 +6686,17 @@ async function main() {
|
|
|
6424
6686
|
const agentDir = readRequiredEnv("PI_CODING_AGENT_DIR");
|
|
6425
6687
|
const version = process.env.DOCYRUS_PI_VERSION || "dev";
|
|
6426
6688
|
const resourceRoot = resolvePackagedPiResourceRoot();
|
|
6427
|
-
const packagedExtensionPaths = resolvePackagedExtensionPaths(resourceRoot);
|
|
6428
|
-
const mcpConfigPath = (0,
|
|
6689
|
+
const packagedExtensionPaths = resolvePackagedExtensionPaths(resourceRoot, "server");
|
|
6690
|
+
const mcpConfigPath = (0, import_node_path7.join)(agentDir, "mcp.json");
|
|
6429
6691
|
const hasPackagedMcpAdapter = packagedExtensionPaths.some((extensionPath) => extensionPath.includes("pi-mcp-adapter"));
|
|
6430
|
-
const envStore = new AgentEnvStore((0,
|
|
6692
|
+
const envStore = new AgentEnvStore((0, import_node_path7.join)(agentDir, "env.json"));
|
|
6431
6693
|
await envStore.hydrateProcessEnv(process.env);
|
|
6432
6694
|
if (hasPackagedMcpAdapter) {
|
|
6433
6695
|
setProcessArgValue("--mcp-config", mcpConfigPath);
|
|
6434
6696
|
}
|
|
6435
|
-
const authStorage = pi.AuthStorage.create((0,
|
|
6697
|
+
const authStorage = pi.AuthStorage.create((0, import_node_path7.join)(agentDir, "auth.json"));
|
|
6436
6698
|
const settingsManager = pi.SettingsManager.create(cwd, agentDir);
|
|
6437
|
-
const modelsJsonPath = (0,
|
|
6699
|
+
const modelsJsonPath = (0, import_node_path7.join)(agentDir, "models.json");
|
|
6438
6700
|
const modelRegistry = new pi.ModelRegistry(authStorage, modelsJsonPath);
|
|
6439
6701
|
const quietStartup = !request.verbose;
|
|
6440
6702
|
if (quietStartup) {
|
|
@@ -6463,7 +6725,11 @@ async function main() {
|
|
|
6463
6725
|
agentDir,
|
|
6464
6726
|
settingsManager,
|
|
6465
6727
|
additionalExtensionPaths: packagedExtensionPaths,
|
|
6466
|
-
|
|
6728
|
+
skillsOverride: ({ skills, diagnostics }) => ({
|
|
6729
|
+
skills: skills.filter((skill) => skill.name !== "docyrus-chrome-devtools-cli"),
|
|
6730
|
+
diagnostics
|
|
6731
|
+
}),
|
|
6732
|
+
systemPrompt: (0, import_node_path7.join)(
|
|
6467
6733
|
resourceRoot,
|
|
6468
6734
|
"prompts",
|
|
6469
6735
|
request.profile === "agent" ? "agent-system.md" : "coder-system.md"
|