@docyrus/docyrus 0.0.63 → 0.0.65

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.
Files changed (36) hide show
  1. package/README.md +19 -0
  2. package/agent-loader.js +165 -21
  3. package/agent-loader.js.map +2 -2
  4. package/main.js +363 -113
  5. package/main.js.map +4 -4
  6. package/package.json +5 -4
  7. package/resources/pi-agent/extensions/browser-tools.ts +1 -1
  8. package/resources/pi-agent/extensions/context.ts +12 -73
  9. package/resources/pi-agent/extensions/control.ts +1 -1
  10. package/resources/pi-agent/extensions/loop.ts +4 -1
  11. package/resources/pi-agent/extensions/pi-bash-live-view/index.ts +1 -1
  12. package/resources/pi-agent/extensions/pi-bash-live-view/package.json +3 -3
  13. package/resources/pi-agent/extensions/pi-fff/README.md +152 -0
  14. package/resources/pi-agent/extensions/pi-fff/VENDORED_FROM.md +7 -0
  15. package/resources/pi-agent/extensions/pi-fff/package.json +53 -0
  16. package/resources/pi-agent/extensions/pi-fff/src/index.ts +820 -0
  17. package/resources/pi-agent/extensions/pi-mcp-adapter/index.ts +1 -1
  18. package/resources/pi-agent/extensions/pi-mcp-adapter/package.json +1 -1
  19. package/resources/pi-agent/extensions/prompt-editor.ts +26 -7
  20. package/resources/pi-agent/extensions/soul.ts +183 -0
  21. package/resources/pi-agent/extensions/todos.ts +1 -1
  22. package/resources/pi-agent/skills/grill-me/SKILL.md +11 -8
  23. package/resources/pi-agent/skills/release-manager/SKILL.md +469 -30
  24. package/resources/pi-agent/souls/boomer-parent.md +23 -0
  25. package/resources/pi-agent/souls/bro.md +22 -0
  26. package/resources/pi-agent/souls/catalog.ts +79 -0
  27. package/resources/pi-agent/souls/caveman.md +21 -0
  28. package/resources/pi-agent/souls/linkedin-influencer.md +60 -0
  29. package/resources/pi-agent/souls/master-yoda.md +22 -0
  30. package/resources/pi-agent/souls/noir-detective.md +24 -0
  31. package/resources/pi-agent/souls/nonsense-engineer.md +23 -0
  32. package/resources/pi-agent/souls/pirate.md +24 -0
  33. package/resources/pi-agent/souls/shakespeare.md +24 -0
  34. package/server-loader.js +803 -93
  35. package/server-loader.js.map +4 -4
  36. package/resources/pi-agent/skills/changelog-generator/SKILL.md +0 -461
package/README.md CHANGED
@@ -362,8 +362,27 @@ Inside the interactive agent TUI:
362
362
  /end-read-only # exit read-only mode and resume normal operation
363
363
  /tasks # browse the canonical project-plan phases, features, and tasks
364
364
  /todos # interactive todo manager
365
+ /souls # list available agent "souls" (communication styles)
366
+ /soul <id> # switch the agent's soul (e.g. caveman, master-yoda, pirate) — takes effect next session
365
367
  ```
366
368
 
369
+ #### Souls
370
+
371
+ A "soul" is a style-only prompt overlay that changes how the agent *talks* without changing what it *does*. Tool usage, Docyrus CLI rules, and structured (`--json`) output are always preserved; souls only affect narrative prose.
372
+
373
+ Select a soul inside the pi agent (`docyrus agent` / `docyrus coder`) with `/soul <id>` and list available souls with `/souls`. The selection is persisted in `<settings-root>/config.json` (same scope as environment/auth) and takes effect on the next agent session.
374
+
375
+ Over HTTP (`docyrus server`):
376
+
377
+ ```bash
378
+ curl http://localhost:3111/api/souls
379
+ curl -X POST http://localhost:3111/api/souls/select \
380
+ -H 'content-type: application/json' \
381
+ -d '{"soulId":"pirate"}'
382
+ ```
383
+
384
+ Full server API reference for **Soul**, **MCP**, and **Skill** endpoints: [`docs/server-api.md`](./docs/server-api.md).
385
+
367
386
  When running through `docyrus server`, `/plan` can be sent through `/api/chat` as normal chat input. If clarification is needed, the server emits a synthetic `ask_user` client tool. Frontends using AI SDK `useChat` should render that tool and submit structured answers back with `addToolOutput`.
368
387
 
369
388
  ### Planning-Model Policy
package/agent-loader.js CHANGED
@@ -1334,6 +1334,60 @@ function createCustomOpenAiProviderConfig(params) {
1334
1334
  ]
1335
1335
  };
1336
1336
  }
1337
+ var DEEPSEEK_BASE_URL = "https://api.deepseek.com";
1338
+ var DEEPSEEK_MODELS = [
1339
+ {
1340
+ id: "deepseek-v4-flash",
1341
+ name: "DeepSeek V4 Flash",
1342
+ cost: {
1343
+ input: 0.14,
1344
+ output: 0.28,
1345
+ cacheRead: 0.028,
1346
+ cacheWrite: 0.14
1347
+ }
1348
+ },
1349
+ {
1350
+ id: "deepseek-v4-pro",
1351
+ name: "DeepSeek V4 Pro",
1352
+ cost: {
1353
+ input: 1.74,
1354
+ output: 3.48,
1355
+ cacheRead: 0.145,
1356
+ cacheWrite: 1.74
1357
+ }
1358
+ }
1359
+ ];
1360
+ function createDeepseekProviderConfig() {
1361
+ return {
1362
+ baseUrl: DEEPSEEK_BASE_URL,
1363
+ apiKey: "env:DEEPSEEK_API_KEY",
1364
+ api: "openai-completions",
1365
+ models: DEEPSEEK_MODELS.map((model) => ({
1366
+ id: model.id,
1367
+ name: model.name,
1368
+ reasoning: true,
1369
+ input: ["text"],
1370
+ contextWindow: 1e6,
1371
+ maxTokens: 384e3,
1372
+ cost: {
1373
+ input: model.cost.input,
1374
+ output: model.cost.output,
1375
+ cacheRead: model.cost.cacheRead,
1376
+ cacheWrite: model.cost.cacheWrite
1377
+ },
1378
+ compat: {
1379
+ supportsReasoningEffort: true,
1380
+ reasoningEffortMap: {
1381
+ minimal: "high",
1382
+ low: "high",
1383
+ medium: "high",
1384
+ high: "high",
1385
+ xhigh: "max"
1386
+ }
1387
+ }
1388
+ }))
1389
+ };
1390
+ }
1337
1391
  function createAzureProviderConfig(params) {
1338
1392
  const providerConfig = {
1339
1393
  baseUrl: params.baseUrl,
@@ -1405,6 +1459,20 @@ async function saveCustomOpenAiConfig(params) {
1405
1459
  }));
1406
1460
  params.settingsManager.setDefaultModelAndProvider("custom-openai", params.modelId.trim());
1407
1461
  }
1462
+ async function saveDeepseekConfig(params) {
1463
+ const apiKey = params.apiKey.trim();
1464
+ const modelId = params.modelId?.trim() || DEEPSEEK_MODELS[0].id;
1465
+ params.authStorage.set("deepseek", {
1466
+ type: "api_key",
1467
+ key: apiKey
1468
+ });
1469
+ await params.envStore.removeMany(["DEEPSEEK_API_KEY"]);
1470
+ await params.envStore.setMany({
1471
+ DEEPSEEK_API_KEY: apiKey
1472
+ });
1473
+ await upsertModelsProvider(params.modelsJsonPath, "deepseek", createDeepseekProviderConfig());
1474
+ params.settingsManager.setDefaultModelAndProvider("deepseek", modelId);
1475
+ }
1408
1476
  async function saveAzureConfig(params) {
1409
1477
  const modelId = params.modelId.trim();
1410
1478
  const useCustomModel = params.useCustomModel ?? false;
@@ -1482,6 +1550,12 @@ async function clearProviderConfig(params) {
1482
1550
  ]);
1483
1551
  await removeModelsProvider(params.modelsJsonPath, "custom-openai");
1484
1552
  }
1553
+ if (params.providerId === "deepseek") {
1554
+ await params.envStore.removeMany([
1555
+ "DEEPSEEK_API_KEY"
1556
+ ]);
1557
+ await removeModelsProvider(params.modelsJsonPath, "deepseek");
1558
+ }
1485
1559
  if (params.providerId === "azure-openai-responses") {
1486
1560
  await params.envStore.removeMany([
1487
1561
  "AZURE_OPENAI_API_KEY",
@@ -1552,6 +1626,7 @@ var PROVIDER_LABELS = {
1552
1626
  mistral: "Mistral",
1553
1627
  minimax: "MiniMax",
1554
1628
  "minimax-cn": "MiniMax CN",
1629
+ deepseek: "DeepSeek",
1555
1630
  huggingface: "Hugging Face",
1556
1631
  opencode: "OpenCode",
1557
1632
  "opencode-go": "OpenCode Go",
@@ -1565,6 +1640,7 @@ var PROVIDER_LABELS = {
1565
1640
  var PROVIDER_HINTS = {
1566
1641
  anthropic: "recommended",
1567
1642
  "custom-openai": "custom base URL + API key",
1643
+ deepseek: "API key (OpenAI-compatible preset)",
1568
1644
  "azure-openai-responses": "API key + base URL/resource + deployment",
1569
1645
  "amazon-bedrock": "AWS profile or access key pair",
1570
1646
  "openai-codex": "browser auth",
@@ -1607,6 +1683,8 @@ function getApiKeyProviderOptions(providerIds) {
1607
1683
  flow = "azure-openai-responses";
1608
1684
  } else if (providerId === "amazon-bedrock") {
1609
1685
  flow = "amazon-bedrock";
1686
+ } else if (providerId === "deepseek") {
1687
+ flow = "deepseek";
1610
1688
  }
1611
1689
  return {
1612
1690
  id: providerId,
@@ -1621,6 +1699,12 @@ function getApiKeyProviderOptions(providerIds) {
1621
1699
  hint: toHint("custom-openai"),
1622
1700
  flow: "custom-openai"
1623
1701
  });
1702
+ baseProviders.push({
1703
+ id: "deepseek",
1704
+ label: toLabel("deepseek"),
1705
+ hint: toHint("deepseek"),
1706
+ flow: "deepseek"
1707
+ });
1624
1708
  const deduped = /* @__PURE__ */ new Map();
1625
1709
  for (const provider of baseProviders) {
1626
1710
  deduped.set(provider.id, provider);
@@ -1673,6 +1757,23 @@ function getProviderFormFields(params) {
1673
1757
  placeholder: "gpt-4o"
1674
1758
  }
1675
1759
  ];
1760
+ case "deepseek":
1761
+ return [
1762
+ {
1763
+ name: "apiKey",
1764
+ title: `${provider.label} API key`,
1765
+ required: true,
1766
+ component: "password"
1767
+ },
1768
+ {
1769
+ name: "modelId",
1770
+ title: "Model",
1771
+ required: true,
1772
+ component: "select",
1773
+ options: DEEPSEEK_MODELS.map((model) => ({ label: model.name, value: model.id })),
1774
+ defaultValue: DEEPSEEK_MODELS[0].id
1775
+ }
1776
+ ];
1676
1777
  case "azure-openai-responses":
1677
1778
  return [
1678
1779
  {
@@ -1944,6 +2045,33 @@ async function runApiKeyProviderFlow(mode, dependencies, provider) {
1944
2045
  modeAny.showStatus(`Configured ${provider.label}`);
1945
2046
  return;
1946
2047
  }
2048
+ case "deepseek": {
2049
+ const apiKeyField = field("apiKey");
2050
+ const modelIdField = field("modelId");
2051
+ const apiKey = await showInput(mode, apiKeyField?.title || "DeepSeek API key");
2052
+ if (!apiKey) {
2053
+ return;
2054
+ }
2055
+ const modelId = await showSelection(
2056
+ mode,
2057
+ modelIdField?.title || "Choose DeepSeek model",
2058
+ (modelIdField?.options ?? DEEPSEEK_MODELS.map((model) => ({ label: model.name, value: model.id }))).map((option) => ({
2059
+ value: option.value,
2060
+ label: option.label
2061
+ }))
2062
+ );
2063
+ if (!modelId) {
2064
+ return;
2065
+ }
2066
+ await saveDeepseekConfig({
2067
+ ...dependencies,
2068
+ apiKey,
2069
+ modelId
2070
+ });
2071
+ await refreshAfterCredentialChange(mode, dependencies.envStore, "deepseek", modelId);
2072
+ modeAny.showStatus(`Configured ${provider.label}`);
2073
+ return;
2074
+ }
1947
2075
  case "azure-openai-responses": {
1948
2076
  const apiKeyField = field("apiKey");
1949
2077
  const configModeField = field("configMode");
@@ -2201,7 +2329,8 @@ async function shouldRunOnboarding(params) {
2201
2329
  knownProviderIds: [
2202
2330
  ...params.browserProviders.map((provider) => provider.id),
2203
2331
  ...params.apiKeyProviderIds,
2204
- "custom-openai"
2332
+ "custom-openai",
2333
+ "deepseek"
2205
2334
  ]
2206
2335
  });
2207
2336
  return !existingProvider;
@@ -2404,6 +2533,32 @@ async function runAzureFlow(clack, pico, dependencies) {
2404
2533
  clack.log.success(`Azure OpenAI configured for ${pico.green(String(modelId).trim())}`);
2405
2534
  return true;
2406
2535
  }
2536
+ async function runDeepseekFlow(clack, pico, dependencies) {
2537
+ const apiKey = await clack.password({
2538
+ message: "Paste your DeepSeek API key:",
2539
+ mask: "\u25CF"
2540
+ });
2541
+ if (clack.isCancel(apiKey) || !apiKey) {
2542
+ return false;
2543
+ }
2544
+ const modelId = await clack.select({
2545
+ message: "Choose a DeepSeek model:",
2546
+ options: DEEPSEEK_MODELS.map((model) => ({
2547
+ value: model.id,
2548
+ label: model.name
2549
+ }))
2550
+ });
2551
+ if (clack.isCancel(modelId) || !modelId) {
2552
+ return false;
2553
+ }
2554
+ await saveDeepseekConfig({
2555
+ ...dependencies,
2556
+ apiKey: String(apiKey).trim(),
2557
+ modelId: String(modelId).trim()
2558
+ });
2559
+ clack.log.success(`DeepSeek configured for ${pico.green(String(modelId).trim())}`);
2560
+ return true;
2561
+ }
2407
2562
  async function runBedrockFlow(clack, pico, dependencies) {
2408
2563
  const authMode = await clack.select({
2409
2564
  message: "How do you want to authenticate with Amazon Bedrock?",
@@ -2489,6 +2644,8 @@ async function runProviderFlow(clack, pico, dependencies, provider) {
2489
2644
  return await runOAuthFlow(clack, pico, dependencies, provider.id);
2490
2645
  case "custom-openai":
2491
2646
  return await runCustomOpenAiFlow(clack, pico, dependencies);
2647
+ case "deepseek":
2648
+ return await runDeepseekFlow(clack, pico, dependencies);
2492
2649
  case "azure-openai-responses":
2493
2650
  return await runAzureFlow(clack, pico, dependencies);
2494
2651
  case "amazon-bedrock":
@@ -2515,7 +2672,8 @@ async function runOnboarding(dependencies) {
2515
2672
  knownProviderIds: [
2516
2673
  ...dependencies.browserProviders.map((provider) => provider.id),
2517
2674
  ...dependencies.apiKeyProviderIds,
2518
- "custom-openai"
2675
+ "custom-openai",
2676
+ "deepseek"
2519
2677
  ]
2520
2678
  });
2521
2679
  const authOptions = [];
@@ -2679,25 +2837,11 @@ async function readPipedStdin() {
2679
2837
  process.stdin.resume();
2680
2838
  });
2681
2839
  }
2682
- function buildTools(profile, cwd, pi) {
2840
+ function buildTools(profile) {
2683
2841
  if (profile === "agent") {
2684
- return [
2685
- pi.createReadTool(cwd),
2686
- pi.createBashTool(cwd),
2687
- pi.createGrepTool(cwd),
2688
- pi.createFindTool(cwd),
2689
- pi.createLsTool(cwd)
2690
- ];
2842
+ return ["read", "bash", "grep", "find", "ls"];
2691
2843
  }
2692
- return [
2693
- pi.createReadTool(cwd),
2694
- pi.createBashTool(cwd),
2695
- pi.createEditTool(cwd),
2696
- pi.createWriteTool(cwd),
2697
- pi.createGrepTool(cwd),
2698
- pi.createFindTool(cwd),
2699
- pi.createLsTool(cwd)
2700
- ];
2844
+ return ["read", "bash", "edit", "write", "grep", "find", "ls"];
2701
2845
  }
2702
2846
  function resolveRequestedModel(params) {
2703
2847
  const { request, modelRegistry } = params;
@@ -2861,7 +3005,7 @@ async function main() {
2861
3005
  agentDir,
2862
3006
  settingsManager,
2863
3007
  additionalExtensionPaths: packagedExtensionPaths,
2864
- systemPrompt: (0, import_node_path4.join)(
3008
+ systemPrompt: process.env.DOCYRUS_PI_SYSTEM_PROMPT_PATH ?? (0, import_node_path4.join)(
2865
3009
  resourceRoot,
2866
3010
  "prompts",
2867
3011
  request.profile === "agent" ? "agent-system.md" : "coder-system.md"
@@ -2869,7 +3013,7 @@ async function main() {
2869
3013
  });
2870
3014
  await resourceLoader.reload();
2871
3015
  spinner.update("Creating session...");
2872
- const tools = buildTools(request.profile, cwd, pi);
3016
+ const tools = buildTools(request.profile);
2873
3017
  const createRuntime = async (options) => {
2874
3018
  const created = await pi.createAgentSession({
2875
3019
  cwd: options.cwd,