@jmcombs/pi-1password 1.0.0 → 1.0.2

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/index.ts CHANGED
@@ -13,16 +13,19 @@
13
13
  * - https://pi.dev/docs/extensions
14
14
  */
15
15
 
16
- import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
17
- import { createBashTool, createLocalBashOperations } from "@earendil-works/pi-coding-agent";
18
- import { Type, type Static } from "typebox";
19
- import { promisify } from "node:util";
20
16
  import { exec } from "node:child_process";
21
17
  import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
22
18
  import { homedir } from "node:os";
23
19
  import { dirname, join } from "node:path";
24
- import { getAgentDir } from "@earendil-works/pi-coding-agent";
25
20
  import { fileURLToPath } from "node:url";
21
+ import { promisify } from "node:util";
22
+ import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
23
+ import {
24
+ createBashTool,
25
+ createLocalBashOperations,
26
+ getAgentDir,
27
+ } from "@earendil-works/pi-coding-agent";
28
+ import { type Static, Type } from "typebox";
26
29
 
27
30
  import {
28
31
  confirmInBorderedPopup,
@@ -133,7 +136,6 @@ async function inspectPluginIfRelevant(command: string): Promise<PluginInspectio
133
136
  return { plugin: firstWord, output: (stdout || "").trim() };
134
137
  } catch (e: unknown) {
135
138
  const error = e as { stderr?: string; message?: string };
136
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
137
139
  const msg = (error.stderr?.trim() ?? error.message) || "Unknown error";
138
140
  return { plugin: firstWord, error: msg };
139
141
  }
@@ -235,10 +237,9 @@ async function resolveShellValue(raw: unknown): Promise<string | null> {
235
237
  async function loadShellEnvMap(): Promise<Record<string, string>> {
236
238
  const home = homedir() || "/tmp";
237
239
  const authPath = join(home, ".pi", "agent", "auth.json");
238
- const map: Record<string, string> = {};
240
+ const map = new Map<string, string>();
239
241
 
240
242
  try {
241
- // eslint-disable-next-line security/detect-non-literal-fs-filename
242
243
  const raw = await readFile(authPath, "utf8");
243
244
  const parsed = JSON.parse(raw) as AuthJson;
244
245
 
@@ -248,15 +249,14 @@ async function loadShellEnvMap(): Promise<Record<string, string>> {
248
249
 
249
250
  const resolved = await resolveShellValue(val);
250
251
  if (resolved !== null) {
251
- // eslint-disable-next-line security/detect-object-injection
252
- map[key] = resolved;
252
+ map.set(key, resolved);
253
253
  }
254
254
  }
255
255
  } catch {
256
256
  // File missing or unreadable — no shell env injection this session
257
257
  }
258
258
 
259
- return map;
259
+ return Object.fromEntries(map);
260
260
  }
261
261
 
262
262
  // In-memory map for the current session (populated on session_start)
@@ -299,19 +299,22 @@ async function addAuthEntry(
299
299
  const authDir = getAgentDir();
300
300
  const authPath = join(authDir, "auth.json");
301
301
 
302
- // eslint-disable-next-line security/detect-non-literal-fs-filename
303
302
  await mkdir(authDir, { recursive: true });
304
303
 
305
- let existing: Record<string, unknown> = {};
304
+ const existing = new Map<string, unknown>();
306
305
  try {
307
- // eslint-disable-next-line security/detect-non-literal-fs-filename
308
306
  const raw = await readFile(authPath, "utf8");
309
- existing = JSON.parse(raw) as Record<string, unknown>;
307
+ const parsed: unknown = JSON.parse(raw);
308
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
309
+ for (const [k, v] of Object.entries(parsed as Record<string, unknown>)) {
310
+ existing.set(k, v);
311
+ }
312
+ }
310
313
  } catch {
311
314
  // File missing or invalid JSON → start fresh
312
315
  }
313
316
 
314
- const alreadyExists = existing[envVar] !== undefined;
317
+ const alreadyExists = existing.has(envVar);
315
318
 
316
319
  if (alreadyExists && !options.overwrite) {
317
320
  return {
@@ -322,13 +325,10 @@ async function addAuthEntry(
322
325
  }
323
326
 
324
327
  // Convention: single quotes around the op:// ref
325
- // eslint-disable-next-line security/detect-object-injection
326
- existing[envVar] = `!op read '${opRef}'`;
328
+ existing.set(envVar, `!op read '${opRef}'`);
327
329
 
328
- const content = JSON.stringify(existing, null, 2) + "\n";
329
- // eslint-disable-next-line security/detect-non-literal-fs-filename
330
+ const content = `${JSON.stringify(Object.fromEntries(existing), null, 2)}\n`;
330
331
  await writeFile(authPath, content, "utf8");
331
- // eslint-disable-next-line security/detect-non-literal-fs-filename
332
332
  await chmod(authPath, 0o600);
333
333
 
334
334
  return { success: true, message: "Entry added.", path: authPath };
@@ -464,7 +464,7 @@ export default async function (pi: ExtensionAPI): Promise<void> {
464
464
  if (info) inspections.push(info);
465
465
  }
466
466
 
467
- let report = formatOpStatus(status) + "\n\n";
467
+ let report = `${formatOpStatus(status)}\n\n`;
468
468
 
469
469
  if (inspections.length > 0) {
470
470
  report += "Plugin configuration:\n";
@@ -598,7 +598,7 @@ export default async function (pi: ExtensionAPI): Promise<void> {
598
598
  const itemItems = [
599
599
  ...items.map((it) => ({
600
600
  value: it.id,
601
- label: `${it.title}${it.category ? "" + it.category : ""}`,
601
+ label: `${it.title}${it.category ? `${it.category}` : ""}`,
602
602
  })),
603
603
  { value: "__cancel", label: "Cancel" },
604
604
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jmcombs/pi-1password",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "1Password integration for the Pi coding agent. Read secrets and run commands with 1Password credential injection via the op CLI.",
5
5
  "homepage": "https://github.com/jmcombs/pi-extensions/tree/main/packages/1password",
6
6
  "repository": {
@@ -46,7 +46,7 @@
46
46
  "typebox": "*"
47
47
  },
48
48
  "devDependencies": {
49
- "@earendil-works/pi-coding-agent": "^0.75.4",
49
+ "@earendil-works/pi-coding-agent": "^0.80.2",
50
50
  "@earendil-works/pi-tui": "*",
51
51
  "typebox": "^1.1.37"
52
52
  }
@@ -70,8 +70,8 @@ export function renderBorderedBox(
70
70
  truncateToWidthFn: (s: string, w: number, e?: string, pad?: boolean) => string,
71
71
  ): string[] {
72
72
  const innerWidth = Math.max(20, width - 4);
73
- const top = theme.fg("accent", "╭" + "─".repeat(width - 2) + "╮");
74
- const bottom = theme.fg("accent", "╰" + "─".repeat(width - 2) + "╯");
73
+ const top = theme.fg("accent", `╭${"─".repeat(width - 2)}╮`);
74
+ const bottom = theme.fg("accent", `╰${"─".repeat(width - 2)}╯`);
75
75
 
76
76
  const rawTitle = theme.fg("accent", theme.bold(title));
77
77
  const titlePadded = truncateToWidthFn(rawTitle, innerWidth, "", true);