@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/agent-loader.js
CHANGED
|
@@ -1132,9 +1132,9 @@ ${J2}${i.trimStart()}`), r2 = 3 + (0, import_node_util.stripVTControlCharacters)
|
|
|
1132
1132
|
});
|
|
1133
1133
|
|
|
1134
1134
|
// src/agent/loader.ts
|
|
1135
|
-
var
|
|
1135
|
+
var import_node_fs2 = require("node:fs");
|
|
1136
1136
|
var import_node_url = require("node:url");
|
|
1137
|
-
var
|
|
1137
|
+
var import_node_path4 = require("node:path");
|
|
1138
1138
|
var import_picocolors4 = __toESM(require_picocolors());
|
|
1139
1139
|
|
|
1140
1140
|
// src/agent/envStore.ts
|
|
@@ -1235,9 +1235,29 @@ var AgentEnvStore = class {
|
|
|
1235
1235
|
}
|
|
1236
1236
|
};
|
|
1237
1237
|
|
|
1238
|
+
// src/agent/packagedExtensions.ts
|
|
1239
|
+
var import_node_fs = require("node:fs");
|
|
1240
|
+
var import_node_path2 = require("node:path");
|
|
1241
|
+
var SERVER_ONLY_PACKAGED_EXTENSION_NAMES = /* @__PURE__ */ new Set(["docyrus-web-browser"]);
|
|
1242
|
+
function isPackagedExtensionEntry(entryName, isDirectory) {
|
|
1243
|
+
return isDirectory || entryName.endsWith(".ts") || entryName.endsWith(".js");
|
|
1244
|
+
}
|
|
1245
|
+
function getPackagedExtensionName(entryName) {
|
|
1246
|
+
return entryName.replace(/\.(ts|js)$/u, "");
|
|
1247
|
+
}
|
|
1248
|
+
function resolvePackagedExtensionPaths(resourceRoot, runtime = "terminal") {
|
|
1249
|
+
const extensionsRoot = (0, import_node_path2.join)(resourceRoot, "extensions");
|
|
1250
|
+
if (!(0, import_node_fs.existsSync)(extensionsRoot)) {
|
|
1251
|
+
return [];
|
|
1252
|
+
}
|
|
1253
|
+
return (0, import_node_fs.readdirSync)(extensionsRoot, {
|
|
1254
|
+
withFileTypes: true
|
|
1255
|
+
}).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));
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1238
1258
|
// src/agent/modelsConfig.ts
|
|
1239
1259
|
var import_promises2 = require("node:fs/promises");
|
|
1240
|
-
var
|
|
1260
|
+
var import_node_path3 = require("node:path");
|
|
1241
1261
|
function createDefaultState2() {
|
|
1242
1262
|
return {
|
|
1243
1263
|
providers: {}
|
|
@@ -1261,7 +1281,7 @@ async function readModelsConfig(filePath) {
|
|
|
1261
1281
|
}
|
|
1262
1282
|
}
|
|
1263
1283
|
async function writeModelsConfig(filePath, state) {
|
|
1264
|
-
const directory = (0,
|
|
1284
|
+
const directory = (0, import_node_path3.dirname)(filePath);
|
|
1265
1285
|
await (0, import_promises2.mkdir)(directory, {
|
|
1266
1286
|
recursive: true,
|
|
1267
1287
|
mode: 448
|
|
@@ -1316,7 +1336,7 @@ function createCustomOpenAiProviderConfig(params) {
|
|
|
1316
1336
|
function createAzureProviderConfig(params) {
|
|
1317
1337
|
const providerConfig = {
|
|
1318
1338
|
baseUrl: params.baseUrl,
|
|
1319
|
-
apiKey: "
|
|
1339
|
+
apiKey: "AZURE_OPENAI_API_KEY"
|
|
1320
1340
|
};
|
|
1321
1341
|
if (params.useCustomModel) {
|
|
1322
1342
|
providerConfig.api = "azure-openai-responses";
|
|
@@ -1345,6 +1365,22 @@ function trimOrUndefined(value) {
|
|
|
1345
1365
|
const trimmed = value?.trim();
|
|
1346
1366
|
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
1347
1367
|
}
|
|
1368
|
+
function normalizeAzureBaseUrl(baseUrl) {
|
|
1369
|
+
const trimmed = baseUrl.trim().replace(/\/+$/, "");
|
|
1370
|
+
try {
|
|
1371
|
+
const url = new URL(trimmed);
|
|
1372
|
+
url.search = "";
|
|
1373
|
+
url.hash = "";
|
|
1374
|
+
if (url.pathname.endsWith("/openai/v1")) {
|
|
1375
|
+
url.pathname = url.pathname.slice(0, -3);
|
|
1376
|
+
} else if (url.pathname.endsWith("/openai/responses")) {
|
|
1377
|
+
url.pathname = url.pathname.slice(0, -10);
|
|
1378
|
+
}
|
|
1379
|
+
return url.toString().replace(/\/+$/, "");
|
|
1380
|
+
} catch {
|
|
1381
|
+
return trimmed.replace(/\/openai\/v1$/i, "/openai").replace(/\/openai\/responses$/i, "/openai");
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1348
1384
|
async function saveGenericApiKey(params) {
|
|
1349
1385
|
params.authStorage.set(params.providerId, {
|
|
1350
1386
|
type: "api_key",
|
|
@@ -1371,6 +1407,7 @@ async function saveCustomOpenAiConfig(params) {
|
|
|
1371
1407
|
async function saveAzureConfig(params) {
|
|
1372
1408
|
const modelId = params.modelId.trim();
|
|
1373
1409
|
const useCustomModel = params.useCustomModel ?? false;
|
|
1410
|
+
const normalizedBaseUrl = normalizeAzureBaseUrl(params.baseUrl);
|
|
1374
1411
|
params.authStorage.set("azure-openai-responses", {
|
|
1375
1412
|
type: "api_key",
|
|
1376
1413
|
key: params.apiKey.trim()
|
|
@@ -1395,7 +1432,7 @@ async function saveAzureConfig(params) {
|
|
|
1395
1432
|
}
|
|
1396
1433
|
await params.envStore.setMany(envValues);
|
|
1397
1434
|
await upsertModelsProvider(params.modelsJsonPath, "azure-openai-responses", createAzureProviderConfig({
|
|
1398
|
-
baseUrl:
|
|
1435
|
+
baseUrl: normalizedBaseUrl,
|
|
1399
1436
|
modelId,
|
|
1400
1437
|
useCustomModel
|
|
1401
1438
|
}));
|
|
@@ -1659,7 +1696,7 @@ function getProviderFormFields(params) {
|
|
|
1659
1696
|
title: "Azure OpenAI base URL",
|
|
1660
1697
|
required: true,
|
|
1661
1698
|
component: "text",
|
|
1662
|
-
placeholder: "https://my-resource.openai.azure.com/openai
|
|
1699
|
+
placeholder: "https://my-resource.openai.azure.com/openai",
|
|
1663
1700
|
dependsOn: { field: "configMode", equals: "base-url" }
|
|
1664
1701
|
},
|
|
1665
1702
|
{
|
|
@@ -1688,8 +1725,8 @@ function getProviderFormFields(params) {
|
|
|
1688
1725
|
name: "apiVersion",
|
|
1689
1726
|
title: "API version",
|
|
1690
1727
|
component: "text",
|
|
1691
|
-
defaultValue: "2025-
|
|
1692
|
-
placeholder: "2025-
|
|
1728
|
+
defaultValue: "2025-04-01-preview",
|
|
1729
|
+
placeholder: "2025-04-01-preview"
|
|
1693
1730
|
}
|
|
1694
1731
|
];
|
|
1695
1732
|
case "amazon-bedrock":
|
|
@@ -1763,9 +1800,14 @@ function getProviderFormFields(params) {
|
|
|
1763
1800
|
}
|
|
1764
1801
|
}
|
|
1765
1802
|
async function refreshSessionAfterCredentialChange(params) {
|
|
1803
|
+
await params.envStore?.hydrateProcessEnv(process.env);
|
|
1766
1804
|
params.modelRegistry.refresh();
|
|
1767
1805
|
const availableModels = params.modelRegistry.getAvailable();
|
|
1768
1806
|
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;
|
|
1807
|
+
if (preferredModel) {
|
|
1808
|
+
await params.session.setModel(preferredModel);
|
|
1809
|
+
return;
|
|
1810
|
+
}
|
|
1769
1811
|
const currentModel = params.session.model;
|
|
1770
1812
|
const currentModelStillAvailable = currentModel ? availableModels.some((model) => model.provider === currentModel.provider && model.id === currentModel.id) : false;
|
|
1771
1813
|
if (currentModel && !currentModelStillAvailable) {
|
|
@@ -1854,11 +1896,12 @@ async function showInput(mode, title, placeholder) {
|
|
|
1854
1896
|
});
|
|
1855
1897
|
});
|
|
1856
1898
|
}
|
|
1857
|
-
async function refreshAfterCredentialChange(mode, preferredProviderId, preferredModelId) {
|
|
1899
|
+
async function refreshAfterCredentialChange(mode, envStore, preferredProviderId, preferredModelId) {
|
|
1858
1900
|
const modeAny = modeAsAny(mode);
|
|
1859
1901
|
await refreshSessionAfterCredentialChange({
|
|
1860
1902
|
session: modeAny.session,
|
|
1861
1903
|
modelRegistry: modeAny.session.modelRegistry,
|
|
1904
|
+
envStore,
|
|
1862
1905
|
preferredProviderId,
|
|
1863
1906
|
preferredModelId
|
|
1864
1907
|
});
|
|
@@ -1896,7 +1939,7 @@ async function runApiKeyProviderFlow(mode, dependencies, provider) {
|
|
|
1896
1939
|
apiKey,
|
|
1897
1940
|
modelId
|
|
1898
1941
|
});
|
|
1899
|
-
await refreshAfterCredentialChange(mode, "custom-openai", modelId);
|
|
1942
|
+
await refreshAfterCredentialChange(mode, dependencies.envStore, "custom-openai", modelId);
|
|
1900
1943
|
modeAny.showStatus(`Configured ${provider.label}`);
|
|
1901
1944
|
return;
|
|
1902
1945
|
}
|
|
@@ -1929,7 +1972,7 @@ async function runApiKeyProviderFlow(mode, dependencies, provider) {
|
|
|
1929
1972
|
} else {
|
|
1930
1973
|
const resourceName = await showInput(mode, resourceNameField?.title || "Azure resource name", resourceNameField?.placeholder);
|
|
1931
1974
|
if (resourceName) {
|
|
1932
|
-
baseUrl = `https://${resourceName}.openai.azure.com/openai
|
|
1975
|
+
baseUrl = `https://${resourceName}.openai.azure.com/openai`;
|
|
1933
1976
|
}
|
|
1934
1977
|
}
|
|
1935
1978
|
if (!baseUrl) {
|
|
@@ -1954,7 +1997,7 @@ async function runApiKeyProviderFlow(mode, dependencies, provider) {
|
|
|
1954
1997
|
apiVersion,
|
|
1955
1998
|
useCustomModel: !builtInModelIds.has(modelId)
|
|
1956
1999
|
});
|
|
1957
|
-
await refreshAfterCredentialChange(mode, "azure-openai-responses", modelId);
|
|
2000
|
+
await refreshAfterCredentialChange(mode, dependencies.envStore, "azure-openai-responses", modelId);
|
|
1958
2001
|
modeAny.showStatus(`Configured ${provider.label}`);
|
|
1959
2002
|
return;
|
|
1960
2003
|
}
|
|
@@ -2017,7 +2060,7 @@ async function runApiKeyProviderFlow(mode, dependencies, provider) {
|
|
|
2017
2060
|
secretAccessKey,
|
|
2018
2061
|
sessionToken
|
|
2019
2062
|
});
|
|
2020
|
-
await refreshAfterCredentialChange(mode, "amazon-bedrock", modelId);
|
|
2063
|
+
await refreshAfterCredentialChange(mode, dependencies.envStore, "amazon-bedrock", modelId);
|
|
2021
2064
|
modeAny.showStatus(`Configured ${provider.label}`);
|
|
2022
2065
|
return;
|
|
2023
2066
|
}
|
|
@@ -2032,7 +2075,7 @@ async function runApiKeyProviderFlow(mode, dependencies, provider) {
|
|
|
2032
2075
|
providerId: provider.id,
|
|
2033
2076
|
apiKey
|
|
2034
2077
|
});
|
|
2035
|
-
await refreshAfterCredentialChange(mode, provider.id);
|
|
2078
|
+
await refreshAfterCredentialChange(mode, dependencies.envStore, provider.id);
|
|
2036
2079
|
modeAny.showStatus(`Configured ${provider.label}`);
|
|
2037
2080
|
}
|
|
2038
2081
|
}
|
|
@@ -2091,7 +2134,7 @@ async function handleInteractiveLogout(mode, dependencies) {
|
|
|
2091
2134
|
...dependencies,
|
|
2092
2135
|
providerId
|
|
2093
2136
|
});
|
|
2094
|
-
await refreshAfterCredentialChange(mode);
|
|
2137
|
+
await refreshAfterCredentialChange(mode, dependencies.envStore);
|
|
2095
2138
|
modeAny.showStatus(`Removed ${getProviderLabel(providerId)}`);
|
|
2096
2139
|
} catch (error) {
|
|
2097
2140
|
modeAny.showError(`Failed to remove ${getProviderLabel(providerId)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -2307,7 +2350,7 @@ async function runAzureFlow(clack, pico, dependencies) {
|
|
|
2307
2350
|
if (configMode === "base-url") {
|
|
2308
2351
|
const baseUrlInput = await clack.text({
|
|
2309
2352
|
message: "Azure OpenAI base URL:",
|
|
2310
|
-
placeholder: "https://my-resource.openai.azure.com/openai
|
|
2353
|
+
placeholder: "https://my-resource.openai.azure.com/openai",
|
|
2311
2354
|
validate: (value) => value?.trim() ? void 0 : "Base URL is required"
|
|
2312
2355
|
});
|
|
2313
2356
|
if (clack.isCancel(baseUrlInput) || !baseUrlInput) {
|
|
@@ -2323,7 +2366,7 @@ async function runAzureFlow(clack, pico, dependencies) {
|
|
|
2323
2366
|
if (clack.isCancel(resourceName) || !resourceName) {
|
|
2324
2367
|
return false;
|
|
2325
2368
|
}
|
|
2326
|
-
baseUrl = `https://${String(resourceName).trim()}.openai.azure.com/openai
|
|
2369
|
+
baseUrl = `https://${String(resourceName).trim()}.openai.azure.com/openai`;
|
|
2327
2370
|
}
|
|
2328
2371
|
const modelId = await clack.text({
|
|
2329
2372
|
message: "Model ID to use:",
|
|
@@ -2342,7 +2385,7 @@ async function runAzureFlow(clack, pico, dependencies) {
|
|
|
2342
2385
|
}
|
|
2343
2386
|
const apiVersion = await clack.text({
|
|
2344
2387
|
message: `API version ${pico.dim("(leave blank to use pi's default)")}:`,
|
|
2345
|
-
placeholder: "2025-
|
|
2388
|
+
placeholder: "2025-04-01-preview"
|
|
2346
2389
|
});
|
|
2347
2390
|
if (clack.isCancel(apiVersion)) {
|
|
2348
2391
|
return false;
|
|
@@ -2591,31 +2634,22 @@ function readLoaderRequest() {
|
|
|
2591
2634
|
}
|
|
2592
2635
|
async function loadPiExports() {
|
|
2593
2636
|
const piPackageDir = readRequiredEnv("PI_PACKAGE_DIR");
|
|
2594
|
-
const moduleUrl = (0, import_node_url.pathToFileURL)((0,
|
|
2637
|
+
const moduleUrl = (0, import_node_url.pathToFileURL)((0, import_node_path4.join)(piPackageDir, "dist", "index.js")).href;
|
|
2595
2638
|
return await import(moduleUrl);
|
|
2596
2639
|
}
|
|
2597
2640
|
function resolvePackagedPiResourceRoot() {
|
|
2598
2641
|
const candidates = [
|
|
2599
|
-
(0,
|
|
2600
|
-
(0,
|
|
2601
|
-
(0,
|
|
2602
|
-
(0,
|
|
2642
|
+
(0, import_node_path4.resolve)(process.cwd(), "apps/api-cli/resources/pi-agent"),
|
|
2643
|
+
(0, import_node_path4.resolve)(__dirname, "../resources/pi-agent"),
|
|
2644
|
+
(0, import_node_path4.resolve)(__dirname, "resources/pi-agent"),
|
|
2645
|
+
(0, import_node_path4.resolve)(process.cwd(), "dist/apps/api-cli/resources/pi-agent")
|
|
2603
2646
|
];
|
|
2604
|
-
const resolved = candidates.find((candidate) => (0,
|
|
2647
|
+
const resolved = candidates.find((candidate) => (0, import_node_fs2.existsSync)(candidate));
|
|
2605
2648
|
if (!resolved) {
|
|
2606
2649
|
throw new Error(`Unable to locate pi agent resources. Checked: ${candidates.join(", ")}`);
|
|
2607
2650
|
}
|
|
2608
2651
|
return resolved;
|
|
2609
2652
|
}
|
|
2610
|
-
function resolvePackagedExtensionPaths(resourceRoot) {
|
|
2611
|
-
const extensionsRoot = (0, import_node_path3.join)(resourceRoot, "extensions");
|
|
2612
|
-
if (!(0, import_node_fs.existsSync)(extensionsRoot)) {
|
|
2613
|
-
return [];
|
|
2614
|
-
}
|
|
2615
|
-
return (0, import_node_fs.readdirSync)(extensionsRoot, {
|
|
2616
|
-
withFileTypes: true
|
|
2617
|
-
}).filter((entry) => entry.isDirectory() || entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".js"))).map((entry) => (0, import_node_path3.join)(extensionsRoot, entry.name)).sort((left, right) => left.localeCompare(right));
|
|
2618
|
-
}
|
|
2619
2653
|
function setProcessArgValue(flag, value) {
|
|
2620
2654
|
const existingIndex = process.argv.indexOf(flag);
|
|
2621
2655
|
if (existingIndex >= 0) {
|
|
@@ -2752,17 +2786,17 @@ async function main() {
|
|
|
2752
2786
|
const agentDir = readRequiredEnv("PI_CODING_AGENT_DIR");
|
|
2753
2787
|
const version = process.env.DOCYRUS_PI_VERSION || "dev";
|
|
2754
2788
|
const resourceRoot = resolvePackagedPiResourceRoot();
|
|
2755
|
-
const packagedExtensionPaths = resolvePackagedExtensionPaths(resourceRoot);
|
|
2756
|
-
const mcpConfigPath = (0,
|
|
2789
|
+
const packagedExtensionPaths = resolvePackagedExtensionPaths(resourceRoot, "terminal");
|
|
2790
|
+
const mcpConfigPath = (0, import_node_path4.join)(agentDir, "mcp.json");
|
|
2757
2791
|
const hasPackagedMcpAdapter = packagedExtensionPaths.some((extensionPath) => extensionPath.includes("pi-mcp-adapter"));
|
|
2758
|
-
const envStore = new AgentEnvStore((0,
|
|
2792
|
+
const envStore = new AgentEnvStore((0, import_node_path4.join)(agentDir, "env.json"));
|
|
2759
2793
|
await envStore.hydrateProcessEnv(process.env);
|
|
2760
2794
|
if (hasPackagedMcpAdapter) {
|
|
2761
2795
|
setProcessArgValue("--mcp-config", mcpConfigPath);
|
|
2762
2796
|
}
|
|
2763
|
-
const authStorage = pi.AuthStorage.create((0,
|
|
2797
|
+
const authStorage = pi.AuthStorage.create((0, import_node_path4.join)(agentDir, "auth.json"));
|
|
2764
2798
|
const settingsManager = pi.SettingsManager.create(cwd, agentDir);
|
|
2765
|
-
const modelsJsonPath = (0,
|
|
2799
|
+
const modelsJsonPath = (0, import_node_path4.join)(agentDir, "models.json");
|
|
2766
2800
|
const initialModelRegistry = new pi.ModelRegistry(authStorage, modelsJsonPath);
|
|
2767
2801
|
const isPrintMode = Boolean(request.print) || !process.stdin.isTTY;
|
|
2768
2802
|
const isInteractive = process.stdin.isTTY && !isPrintMode;
|
|
@@ -2826,7 +2860,7 @@ async function main() {
|
|
|
2826
2860
|
agentDir,
|
|
2827
2861
|
settingsManager,
|
|
2828
2862
|
additionalExtensionPaths: packagedExtensionPaths,
|
|
2829
|
-
systemPrompt: (0,
|
|
2863
|
+
systemPrompt: (0, import_node_path4.join)(
|
|
2830
2864
|
resourceRoot,
|
|
2831
2865
|
"prompts",
|
|
2832
2866
|
request.profile === "agent" ? "agent-system.md" : "coder-system.md"
|