@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 +23 -23
- package/package.json +2 -2
- package/ui/bordered-popups.ts +2 -2
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
326
|
-
existing[envVar] = `!op read '${opRef}'`;
|
|
328
|
+
existing.set(envVar, `!op read '${opRef}'`);
|
|
327
329
|
|
|
328
|
-
const content = JSON.stringify(existing, null, 2)
|
|
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)
|
|
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 ?
|
|
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.
|
|
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.
|
|
49
|
+
"@earendil-works/pi-coding-agent": "^0.80.2",
|
|
50
50
|
"@earendil-works/pi-tui": "*",
|
|
51
51
|
"typebox": "^1.1.37"
|
|
52
52
|
}
|
package/ui/bordered-popups.ts
CHANGED
|
@@ -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", "
|
|
74
|
-
const bottom = theme.fg("accent", "
|
|
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);
|