@docyrus/docyrus 0.0.32 → 0.0.34

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docyrus/docyrus",
3
- "version": "0.0.32",
3
+ "version": "0.0.34",
4
4
  "private": false,
5
5
  "description": "Docyrus API CLI",
6
6
  "main": "./main.js",
@@ -0,0 +1,113 @@
1
+ ---
2
+ name: officecli
3
+ description: Use OfficeCLI to create, inspect, validate, and modify Office documents (.docx, .xlsx, .pptx) from the terminal. Use when the user wants Office document automation, extraction, validation, or editing.
4
+ ---
5
+
6
+ # OfficeCLI
7
+
8
+ OfficeCLI is available in Docyrus pi sessions as a local command-line tool for Word, Excel, and PowerPoint files.
9
+
10
+ Use the CLI directly in this environment. Do not run `officecli mcp ...` unless the user explicitly asks to register OfficeCLI with another editor or agent.
11
+
12
+ ## First Principles
13
+
14
+ - Prefer structured output by adding `--json` whenever you need to inspect or transform results.
15
+ - Work from higher-level commands down:
16
+ - L1 read and inspection: `view`, `get`, `query`, `validate`
17
+ - L2 DOM edits: `set`, `add`, `remove`, `move`, `batch`
18
+ - L3 raw XML fallback: `raw`, `raw-set`, `add-part`
19
+ - When unsure about element names, property names, or allowed value formats, run help instead of guessing.
20
+ - After making changes, run `officecli validate <file>` and, when useful, `officecli view <file> issues`.
21
+ - For multi-step edits on a single file, use `open` and `close` to keep the document in memory.
22
+
23
+ ## Verify Availability
24
+
25
+ ```bash
26
+ officecli --version
27
+ officecli --help
28
+ ```
29
+
30
+ If a command fails unexpectedly, inspect the help for the specific document type before trying alternatives.
31
+
32
+ ## Help-First Workflow
33
+
34
+ ```bash
35
+ officecli docx set
36
+ officecli docx set paragraph
37
+ officecli xlsx set cell.value
38
+ officecli pptx add chart
39
+ officecli pptx query
40
+ ```
41
+
42
+ Use the deepest help entry you already know. One help lookup is better than guessing and retrying.
43
+
44
+ ## Common Commands
45
+
46
+ Create a new document:
47
+
48
+ ```bash
49
+ officecli create report.docx
50
+ officecli create model.xlsx
51
+ officecli create deck.pptx
52
+ ```
53
+
54
+ Inspect document structure or extracted text:
55
+
56
+ ```bash
57
+ officecli view report.docx outline
58
+ officecli view report.docx text --max-lines 80
59
+ officecli view deck.pptx issues
60
+ officecli get deck.pptx /slide[1] --depth 1 --json
61
+ officecli query model.xlsx 'cell[value~=Revenue]' --json
62
+ ```
63
+
64
+ Modify content:
65
+
66
+ ```bash
67
+ officecli set report.docx /body/p[1] --prop style=Heading1 --prop text="Executive Summary"
68
+ officecli add deck.pptx / --type slide --prop title="Q4 Report"
69
+ officecli add deck.pptx /slide[1] --type shape --prop text="Revenue grew 25%" --prop x=2cm --prop y=5cm
70
+ officecli set model.xlsx /Sheet1/A1 --prop value="Name" --prop bold=true
71
+ ```
72
+
73
+ Batch related changes:
74
+
75
+ ```bash
76
+ echo '[{"command":"set","path":"/Sheet1/A1","props":{"value":"Name","bold":"true"}},{"command":"set","path":"/Sheet1/B1","props":{"value":"Score","bold":"true"}}]' | officecli batch model.xlsx --json
77
+ ```
78
+
79
+ Keep a document open for a longer edit session:
80
+
81
+ ```bash
82
+ officecli open report.docx
83
+ officecli set report.docx /body/p[2] --prop text="Updated paragraph"
84
+ officecli close report.docx
85
+ ```
86
+
87
+ ## Practical Guidance
88
+
89
+ - Prefer `view`, `get`, or `query` to understand the document before editing it.
90
+ - Use `query` to locate matching elements instead of hard-coding guessed paths.
91
+ - Keep outputs bounded for large files with flags such as `--max-lines`, `--start`, or `--end`.
92
+ - Path indexing is 1-based: `/body/p[3]` means the third paragraph.
93
+ - Use `batch` when several changes should be applied in one save cycle.
94
+ - Use `watch` for PowerPoint only when the user explicitly wants a live preview flow.
95
+
96
+ ## When Raw XML Is Appropriate
97
+
98
+ Only fall back to `raw` or `raw-set` when:
99
+
100
+ - the higher-level commands cannot express the change,
101
+ - you already inspected the target part with `get` or `raw`,
102
+ - and you are prepared to validate immediately afterwards.
103
+
104
+ ## Validation Checklist
105
+
106
+ After editing:
107
+
108
+ ```bash
109
+ officecli validate <file>
110
+ officecli view <file> issues
111
+ ```
112
+
113
+ If validation fails, fix the issue before presenting the result as complete.
package/server-loader.js CHANGED
@@ -3515,7 +3515,7 @@ function createCustomOpenAiProviderConfig(params) {
3515
3515
  function createAzureProviderConfig(params) {
3516
3516
  const providerConfig = {
3517
3517
  baseUrl: params.baseUrl,
3518
- apiKey: "env:AZURE_OPENAI_API_KEY"
3518
+ apiKey: "AZURE_OPENAI_API_KEY"
3519
3519
  };
3520
3520
  if (params.useCustomModel) {
3521
3521
  providerConfig.api = "azure-openai-responses";
@@ -3544,6 +3544,22 @@ function trimOrUndefined(value) {
3544
3544
  const trimmed = value?.trim();
3545
3545
  return trimmed && trimmed.length > 0 ? trimmed : void 0;
3546
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
+ }
3547
3563
  async function saveGenericApiKey(params) {
3548
3564
  params.authStorage.set(params.providerId, {
3549
3565
  type: "api_key",
@@ -3570,6 +3586,7 @@ async function saveCustomOpenAiConfig(params) {
3570
3586
  async function saveAzureConfig(params) {
3571
3587
  const modelId = params.modelId.trim();
3572
3588
  const useCustomModel = params.useCustomModel ?? false;
3589
+ const normalizedBaseUrl = normalizeAzureBaseUrl(params.baseUrl);
3573
3590
  params.authStorage.set("azure-openai-responses", {
3574
3591
  type: "api_key",
3575
3592
  key: params.apiKey.trim()
@@ -3594,7 +3611,7 @@ async function saveAzureConfig(params) {
3594
3611
  }
3595
3612
  await params.envStore.setMany(envValues);
3596
3613
  await upsertModelsProvider(params.modelsJsonPath, "azure-openai-responses", createAzureProviderConfig({
3597
- baseUrl: params.baseUrl.trim(),
3614
+ baseUrl: normalizedBaseUrl,
3598
3615
  modelId,
3599
3616
  useCustomModel
3600
3617
  }));
@@ -3841,7 +3858,7 @@ function getProviderFormFields(params) {
3841
3858
  title: "Azure OpenAI base URL",
3842
3859
  required: true,
3843
3860
  component: "text",
3844
- placeholder: "https://my-resource.openai.azure.com/openai/v1",
3861
+ placeholder: "https://my-resource.openai.azure.com/openai",
3845
3862
  dependsOn: { field: "configMode", equals: "base-url" }
3846
3863
  },
3847
3864
  {
@@ -3870,8 +3887,8 @@ function getProviderFormFields(params) {
3870
3887
  name: "apiVersion",
3871
3888
  title: "API version",
3872
3889
  component: "text",
3873
- defaultValue: "2025-03-01-preview",
3874
- placeholder: "2025-03-01-preview"
3890
+ defaultValue: "2025-04-01-preview",
3891
+ placeholder: "2025-04-01-preview"
3875
3892
  }
3876
3893
  ];
3877
3894
  case "amazon-bedrock":
@@ -4063,7 +4080,7 @@ async function applyProviderLogin(params) {
4063
4080
  return { providerId: provider.id, preferredModelId: params.input.modelId };
4064
4081
  }
4065
4082
  case "azure-openai-responses": {
4066
- const baseUrl = params.input.baseUrl ?? (params.input.resourceName ? `https://${params.input.resourceName}.openai.azure.com/openai/v1` : void 0);
4083
+ const baseUrl = params.input.baseUrl ?? (params.input.resourceName ? `https://${params.input.resourceName}.openai.azure.com/openai` : void 0);
4067
4084
  if (!baseUrl) {
4068
4085
  throw new Error("Azure login requires either baseUrl or resourceName.");
4069
4086
  }
@@ -4103,9 +4120,14 @@ async function applyProviderLogin(params) {
4103
4120
  }
4104
4121
  }
4105
4122
  async function refreshSessionAfterCredentialChange(params) {
4123
+ await params.envStore?.hydrateProcessEnv(process.env);
4106
4124
  params.modelRegistry.refresh();
4107
4125
  const availableModels = params.modelRegistry.getAvailable();
4108
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
+ }
4109
4131
  const currentModel = params.session.model;
4110
4132
  const currentModelStillAvailable = currentModel ? availableModels.some((model) => model.provider === currentModel.provider && model.id === currentModel.id) : false;
4111
4133
  if (currentModel && !currentModelStillAvailable) {
@@ -5436,6 +5458,7 @@ async function createAgentServer(params) {
5436
5458
  await refreshSessionAfterCredentialChange({
5437
5459
  session: activeSession,
5438
5460
  modelRegistry,
5461
+ envStore: authRuntime.envStore,
5439
5462
  preferredProviderId: result.providerId,
5440
5463
  preferredModelId: result.preferredModelId
5441
5464
  });
@@ -5467,6 +5490,7 @@ async function createAgentServer(params) {
5467
5490
  await refreshSessionAfterCredentialChange({
5468
5491
  session: activeSession,
5469
5492
  modelRegistry,
5493
+ envStore: authRuntime.envStore,
5470
5494
  preferredProviderId: providerId
5471
5495
  });
5472
5496
  }
@@ -5498,7 +5522,8 @@ async function createAgentServer(params) {
5498
5522
  modelRegistry.refresh();
5499
5523
  await refreshSessionAfterCredentialChange({
5500
5524
  session: activeSession,
5501
- modelRegistry
5525
+ modelRegistry,
5526
+ envStore: authRuntime.envStore
5502
5527
  });
5503
5528
  return c.json({
5504
5529
  ok: true,