@drdoc-com/pi-drdoc 1.0.2 → 1.0.4

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/README.md CHANGED
@@ -60,11 +60,18 @@ Example:
60
60
  /drdoc_login https://drdoc.com demo password "" 1
61
61
  ```
62
62
 
63
- And signout/signout:
63
+ And signout/logout:
64
64
  ```bash
65
65
  /drdoc_logout
66
66
  ```
67
67
 
68
+ ### Pi Agent Tool Calling
69
+
70
+ Example:
71
+ ```
72
+ Suche im Dr.DOC Archiv "rec" alle Rechnungen von Firma Amazon aus diesem Jahr.
73
+ ```
74
+
68
75
  ## Configuration
69
76
 
70
77
  The plugin utilizes configuration options supplied by the Dr.DOC client or environment variables.
@@ -77,10 +84,19 @@ The plugin utilizes configuration options supplied by the Dr.DOC client or envir
77
84
  | `DRDOC_CONFIG_DIR` (alt. `PI_CONFIG_DIR`) | Custom directory for config files | `~/.pi/agent` |
78
85
  | `DRDOC_DOWNLOAD_DIR` | Custom directory for downloaded files | `~/.drdoc/downloads` |
79
86
  | `DRDOC_IGNORE_SSL` | Ignore TLS/SSL Errors (Set `NODE_TLS_REJECT_UNAUTHORIZED=0`) | `` |
87
+ | `DRDOC_AI_FS` | Dr.DOC IMPORT_ASCII FieldSelection Name for Field Descriptions. | `STD_AI_INVOICE_IN`, `DD_FIELD_DESC`, `STD_FIELD_DESC` |
80
88
  | `DRDOC_DEBUG` | Enable Debugging | `` |
81
89
 
82
90
  ---
83
91
 
92
+ ### Security Notes
93
+ * Pi Agent is designed as a **personal** AI agent. Users must operate their own private Pi Agent instance rather than using an instance hosted on the Dr.DOC Web Server.
94
+ * Credential Persistence (/drdoc_login): When using the Dr.DOC AI Chat with Pi configured as the AI endpoint (via `@drdoc-com/pi-openai-api-wrapper`), the `/drdoc_login` command *MUST NOT* be executed. Authentication credentials within the Pi Agent instance are persistent and could potentially be exposed to other users sharing the same instance.
95
+ * Dedicated Service Account: Use a dedicated Dr.DOC user account with limited permissions (e.g. *Datensatzspezifische Berechtigungen*) based on the principle of least privilege (*"need-to-know"*) specifically for AI tasks and the `/drdoc_login` command.
96
+ * Containerized Deployment: Whenever possible, run Pi Agent inside an isolated container environment (e.g., Docker, Podman) to ensure process isolation and security boundaries.
97
+
98
+ ---
99
+
84
100
  ## License
85
101
 
86
102
  This project is licensed under the Apache License 2.0.
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@drdoc-com/pi-drdoc",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Dr.DOC DMS Integration Package for PI Agent",
5
5
  "type": "module",
6
6
  "license": "Apache License 2.0",
7
7
  "keywords": [
8
8
  "pi-package",
9
9
  "pi-agent",
10
- "drdoc",
11
10
  "rest-api",
12
11
  "skill",
13
- "dms",
14
- "Dr.DOC"
12
+ "drdoc",
13
+ "Dr.DOC",
14
+ "dms"
15
15
  ],
16
16
  "private": false,
17
17
  "pi": {
@@ -31,7 +31,7 @@
31
31
  "author": "Dr.DOC GmbH, DE-80802 Munich",
32
32
  "devDependencies": {
33
33
  "typescript": "^7.0.2",
34
- "@types/node": "^26.2.0"
34
+ "@types/node": "^24.0.0"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@earendil-works/pi-coding-agent": "*"
@@ -163,7 +163,8 @@ export class DrDocClient {
163
163
  try {
164
164
  const dataToSave = JSON.stringify(this.config, null, 2);
165
165
  fs.writeFileSync(this.storageFilePath, dataToSave, "utf-8");
166
- msgLog('DD Anmeldedaten wurden gespeichert unter: ', this.storageFilePath);
166
+ if (process.env.DRDOC_DEBUG)
167
+ msgLog('Dr.DOC Anmeldedaten wurden gespeichert unter: ', this.storageFilePath);
167
168
  } catch (error) {
168
169
  throw new Error(`Fehler beim Speichern der Anmeldedaten: ${error instanceof Error ? error.message : String(error)}`);
169
170
  }
@@ -192,8 +193,11 @@ export class DrDocClient {
192
193
  if (setCookie) {
193
194
  const match = setCookie.match(/uid=([^;]+)/);
194
195
  if (match) {
196
+ const oldCookieValue = this.config.sessionCookie;
195
197
  this.config.sessionCookie = `uid=${match[1]}`;
196
- // this.saveCredentials(this.config);
198
+ // bei Cookie Änderung, Cookie uid explizit abspeichern
199
+ if (oldCookieValue != this.config.sessionCookie)
200
+ this.saveCredentials();
197
201
  }
198
202
  }
199
203
  }
@@ -330,11 +334,13 @@ export class DrDocClient {
330
334
  // Dauerhaftes Speichern der gesamten DrDocConfig nach erfolgreichem Login
331
335
  this.saveCredentials();
332
336
 
333
- msgLog('DD: Sign in OK:', this.config);
337
+ if (process.env.DRDOC_DEBUG)
338
+ msgLog('DD: Sign in OK: ', JSON.stringify(this.config));
334
339
  }
335
340
  else {
336
-
337
- console.warn('DD: Sign in ERR:', this.config);
341
+ //if (process.env.DRDOC_DEBUG)
342
+ if (process.env.DRDOC_DEBUG)
343
+ msgLog('DD: Sign in ERROR: ' + JSON.stringify(this.config));
338
344
  }
339
345
 
340
346
  return response;
@@ -349,11 +355,14 @@ export class DrDocClient {
349
355
 
350
356
  // Überprüfung auf erfolgreiche Anmeldung
351
357
  if (response && !response.HasError) {
352
- msgLog('DD: State OK:', this.config);
358
+ if (process.env.DRDOC_DEBUG)
359
+ msgLog('Dr.DOC: State OK:', this.config);
353
360
  return true;
354
361
  }
355
362
  else {
356
- msgError('DD: State ERR:', this.config);
363
+ msgError('Bitte erneut anmelden mit Slash Command `/drdoc_login`');
364
+ if (process.env.DRDOC_DEBUG)
365
+ msgLog('Dr.DOC: State ERROR: ' + JSON.stringify(this.config));
357
366
  return false;
358
367
  }
359
368
  }
package/src/index.ts CHANGED
@@ -17,7 +17,7 @@ export default function (pi: any): void {
17
17
 
18
18
  // Login
19
19
  pi.registerCommand("drdoc_login", {
20
- description: "Benutzer anmelden in Dr.DOC über die REST API und speichert die Session.",
20
+ description: "Benutzer anmelden in Dr.DOC über die REST API und speichert die Session: `/drdoc_login <baseUrl> <username> <password> <totp> <ignoreSSL:1,0>`",
21
21
  handler: async (args: string, ctx: any) => {
22
22
  // Entfernen leerer Strings nach dem String-Split
23
23
  const parts = args.trim().split(/\s+/); //.filter(Boolean);
@@ -34,18 +34,18 @@ export default function (pi: any): void {
34
34
  try {
35
35
  //initializeDrDocClient({ baseUrl, username, password, totp, ignoreSSL });
36
36
  //const client = new DrDocClient({ baseUrl, username, password, totp, ignoreSSL });
37
- const client = await getClient({ baseUrl, username, password, totp, ignoreSSL: (ignoreSSL == '1' || ignoreSSL == 'true') });
37
+ const client = await getClient({ baseUrl, username, password, totp, ignoreSSL: (ignoreSSL == '1' || ignoreSSL == 'true') }, true);
38
38
  if (process.env.DRDOC_DEBUG)
39
39
  msgLog('Client: ', client);
40
40
 
41
- const response = await client.signin(username, password, totp);
41
+ /*const response = await client.signin(username, password, totp);
42
42
 
43
43
  if (response.HasError) {
44
44
  msgError(`Anmeldung fehlgeschlagen: ${response.Error?.Message}`);
45
45
  return;
46
46
  }
47
47
 
48
- msgInfo("Erfolgreich an Dr.DOC angemeldet. Die Session ist aktiv.");
48
+ msgInfo("Erfolgreich an Dr.DOC angemeldet. Die Session ist aktiv.");*/
49
49
  } catch (err: any) {
50
50
  msgError(`Fehler bei der Verbindung: ${err.message}`);
51
51
  }
package/src/tools.ts CHANGED
@@ -11,13 +11,27 @@ let clientInstance: DrDocClient | null = null;
11
11
  */
12
12
  export async function getClient(config: DrDocConfig = {} as DrDocConfig, force: Boolean = false): Promise<DrDocClient> {
13
13
  if (!clientInstance || force) {
14
- msgInfo('getClient: init instance');
14
+ if (process.env.DRDOC_DEBUG)
15
+ msgInfo('getClient: init instance');
15
16
  clientInstance = new DrDocClient(config);
17
+
16
18
  // Verbindung testen
17
- if (await clientInstance.state())
18
- msgInfo('getClient: state ok');
19
+ if (await clientInstance.state()) {
20
+ msgInfo('Bereits in Dr.DOC angemeldet. Die Session ist aktiv.');
21
+ }
19
22
  else {
20
- throw new Error("getClient: DrDocClient ist nicht initialisiert. Bitte vorher den Befehl /drdoc_login ausführen.");
23
+ const response = await clientInstance.signin(config.username, config.password, config.totp);
24
+ if (response.HasError)
25
+ throw new Error("getClient: DrDocClient ist nicht initialisiert. Bitte vorher den Befehl /drdoc_login ausführen.");
26
+
27
+ msgInfo("Erfolgreich an Dr.DOC angemeldet. Die Session ist aktiv.");
28
+
29
+ // Verbindung testen
30
+ /*if (await clientInstance.state())
31
+ msgInfo('getClient: state ok');
32
+ else {
33
+
34
+ }*/
21
35
  }
22
36
  }
23
37
  return clientInstance;
@@ -138,8 +152,10 @@ export const drdocTools = [
138
152
  if (process.env.DRDOC_DEBUG)
139
153
  msgLog('drdoc_properties_fields:', args);
140
154
  return safeExecuteClient(["archive"], args, async (client, safeArgs) => {
141
- const defNameArray = ['STD_AI_INVOICE_IN', 'DD_FIELD_DESC', 'STD_FIELD_DESC'];
155
+ const defNameArray = [process.env.DRDOC_AI_FS, 'STD_AI_INVOICE_IN', 'DD_FIELD_DESC', 'STD_FIELD_DESC'];
142
156
  for (let defName of defNameArray) {
157
+ if (!defName)
158
+ continue;
143
159
  const fs = await client.getFieldSelection(safeArgs.archive, "IMPORT_ASCII", defName);
144
160
  if (process.env.DRDOC_DEBUG)
145
161
  msgLog('props:', fs);
@@ -183,8 +199,8 @@ Beispiele für Suchoperatoren:
183
199
  Datumsformat: DD.MM.YYYY
184
200
  Zahlenformat: 0.00
185
201
  Variablen:
186
- - %DY% Variable für Datumsbereich im aktuellen/diesen Jahr
187
- - %DMY% Variable für Datumsbereich im aktuellen/diesen Monat
202
+ - %DY% Variable für Datumsbereich im aktuellen/diesen Jahr (wird z.B. zu: *.2021)
203
+ - %DMY% Variable für Datumsbereich im aktuellen/diesen Monat (wird z.B. zu: *.01.2021)
188
204
  - %DWY% Variable für Datumsbereich in der aktuellen/diesen Woche (7 Tage)
189
205
  - %B% Variable für angemeldeten Benutzer
190
206
  - %D% Variable für aktuelles Datum (heutiger Tag)