pi2dsh 0.12.4 → 0.13.1

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 (33) hide show
  1. package/README.md +73 -12
  2. package/README.zh.md +61 -10
  3. package/dist/{analyzer-CXNbeBAe.mjs → analyzer-CJFwQlSG.mjs} +2 -2
  4. package/dist/{analyzer-CXNbeBAe.mjs.map → analyzer-CJFwQlSG.mjs.map} +1 -1
  5. package/dist/cli.mjs +2 -2
  6. package/dist/client.js +187 -0
  7. package/dist/compat/pi-ai.d.mts +2281 -5
  8. package/dist/compat/pi-ai.d.mts.map +1 -1
  9. package/dist/compat/pi-ai.mjs +2 -2
  10. package/dist/compat/pi-coding-agent.mjs +1 -1
  11. package/dist/{credentials-oauth-BakY-0PA.mjs → credentials-oauth-Txs6oew8.mjs} +13 -6
  12. package/dist/credentials-oauth-Txs6oew8.mjs.map +1 -0
  13. package/dist/credentials-oauth.mjs +1 -1
  14. package/dist/host.mjs +1 -1
  15. package/dist/index.d.mts.map +1 -1
  16. package/dist/index.mjs +3 -3
  17. package/dist/{mcp-config-CZepacin.mjs → mcp-config-_idn-pzI.mjs} +8 -7
  18. package/dist/mcp-config-_idn-pzI.mjs.map +1 -0
  19. package/dist/pi-ai-D7PqVeWs.mjs +11717 -0
  20. package/dist/pi-ai-D7PqVeWs.mjs.map +1 -0
  21. package/dist/{pi-coding-agent-D9skobb6.mjs → pi-coding-agent-BVZu0dHG.mjs} +0 -0
  22. package/dist/{pi-coding-agent-D9skobb6.mjs.map → pi-coding-agent-BVZu0dHG.mjs.map} +1 -1
  23. package/dist/{runtime-DH0zEUpu.mjs → runtime-DEjs_Qlf.mjs} +176 -23
  24. package/dist/runtime-DEjs_Qlf.mjs.map +1 -0
  25. package/dist/runtime.d.mts +6 -0
  26. package/dist/runtime.d.mts.map +1 -1
  27. package/dist/runtime.mjs +1 -1
  28. package/package.json +31 -32
  29. package/dist/credentials-oauth-BakY-0PA.mjs.map +0 -1
  30. package/dist/mcp-config-CZepacin.mjs.map +0 -1
  31. package/dist/pi-ai-BA3V_J0V.mjs +0 -3104
  32. package/dist/pi-ai-BA3V_J0V.mjs.map +0 -1
  33. package/dist/runtime-DH0zEUpu.mjs.map +0 -1
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as resolvePiPackage } from "./source-0sA5z08z.mjs";
3
- import { a as CONTEXT_RULES, d as UI_CONTEXT_RULES, i as API_RULES, n as convertPiMcpConfig, o as EVENT_RULES, r as renderMcpPatch, s as HOST_IMPORT_RULES } from "./mcp-config-CZepacin.mjs";
3
+ import { a as CONTEXT_RULES, d as UI_CONTEXT_RULES, i as API_RULES, n as convertPiMcpConfig, o as EVENT_RULES, r as renderMcpPatch, s as HOST_IMPORT_RULES } from "./mcp-config-_idn-pzI.mjs";
4
4
  import { writeFileSync } from "node:fs";
5
5
  import { parseArgs } from "node:util";
6
6
  //#region src/cli.ts
@@ -75,7 +75,7 @@ async function main() {
75
75
  if (command !== "inspect" || source === void 0) throw new Error(`invalid command\n\n${usage()}`);
76
76
  const pkg = await resolvePiPackage(source);
77
77
  try {
78
- const { analyzePackage } = await import("./analyzer-CXNbeBAe.mjs");
78
+ const { analyzePackage } = await import("./analyzer-CJFwQlSG.mjs");
79
79
  const report = await analyzePackage(pkg);
80
80
  console.log(parsed.values.json ? JSON.stringify(report, null, 2) : reportText(report));
81
81
  if (report.verdict === "blocked") process.exitCode = 2;
package/dist/client.js CHANGED
@@ -316,8 +316,194 @@ window.__ModuleLoader__.load({
316
316
  flexDirection: "column",
317
317
  gap: "4px",
318
318
  padding: "4px 2px"
319
+ },
320
+ imageTool: {
321
+ margin: "4px 0",
322
+ overflow: "hidden",
323
+ borderRadius: "8px",
324
+ border: "1px solid rgba(120,120,130,0.22)",
325
+ background: "var(--dsh-color-bg-subtle, rgba(120,120,130,0.06))",
326
+ color: "var(--dsh-color-text, inherit)",
327
+ font: "400 12px/1.5 system-ui, sans-serif"
328
+ },
329
+ imageToolToggle: {
330
+ width: "100%",
331
+ display: "flex",
332
+ alignItems: "center",
333
+ gap: "8px",
334
+ padding: "8px 10px",
335
+ cursor: "pointer",
336
+ border: "none",
337
+ background: "transparent",
338
+ color: "inherit",
339
+ textAlign: "left",
340
+ font: "500 12px/1.5 system-ui, sans-serif"
341
+ },
342
+ imageToolStatus: {
343
+ color: "#2FBC44",
344
+ fontSize: "10px"
345
+ },
346
+ imageToolSummary: {
347
+ opacity: .62,
348
+ overflow: "hidden",
349
+ textOverflow: "ellipsis",
350
+ whiteSpace: "nowrap"
351
+ },
352
+ imageToolBody: {
353
+ display: "flex",
354
+ flexDirection: "column",
355
+ gap: "8px",
356
+ padding: "0 10px 10px",
357
+ borderTop: "1px solid rgba(120,120,130,0.14)"
358
+ },
359
+ imageToolText: {
360
+ margin: "8px 0 0",
361
+ whiteSpace: "pre-wrap",
362
+ wordBreak: "break-word",
363
+ opacity: .82
364
+ },
365
+ imageGrid: {
366
+ display: "flex",
367
+ flexWrap: "wrap",
368
+ gap: "8px"
369
+ },
370
+ imageFrame: {
371
+ display: "block",
372
+ maxWidth: "min(320px, 100%)",
373
+ maxHeight: "320px",
374
+ borderRadius: "8px",
375
+ objectFit: "contain",
376
+ background: "rgba(0,0,0,0.08)"
377
+ },
378
+ imageError: {
379
+ padding: "12px",
380
+ color: "#F63218"
319
381
  }
320
382
  };
383
+ /** Pull one image through DSH's own session-authorized attachment RPC. */
384
+ function AuthorizedToolImage({ sessionId, attachment }) {
385
+ const [url, setUrl] = (0, react.useState)(void 0);
386
+ const [failed, setFailed] = (0, react.useState)(false);
387
+ (0, react.useEffect)(() => {
388
+ const controller = new AbortController();
389
+ let objectUrl;
390
+ (async () => {
391
+ try {
392
+ const response = await fetch("/api/session.attachment", {
393
+ method: "POST",
394
+ headers: { "content-type": "application/json" },
395
+ signal: controller.signal,
396
+ body: JSON.stringify({
397
+ type: "client-request",
398
+ rpcId: `pi2dsh-image-${Date.now()}-${Math.random().toString(36).slice(2)}`,
399
+ method: "session.attachment",
400
+ payload: {
401
+ sessionId,
402
+ attachmentId: attachment.attachmentId
403
+ }
404
+ })
405
+ });
406
+ const envelope = await response.json();
407
+ const data = envelope.result?.ok === true ? envelope.result.value?.data : void 0;
408
+ if (!response.ok || typeof data !== "string") throw new Error("attachment unavailable");
409
+ const binary = atob(data);
410
+ const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
411
+ objectUrl = URL.createObjectURL(new Blob([bytes], { type: attachment.mediaType }));
412
+ if (!controller.signal.aborted) setUrl(objectUrl);
413
+ } catch {
414
+ if (!controller.signal.aborted) setFailed(true);
415
+ }
416
+ })();
417
+ return () => {
418
+ controller.abort();
419
+ if (objectUrl !== void 0) URL.revokeObjectURL(objectUrl);
420
+ };
421
+ }, [
422
+ sessionId,
423
+ attachment.attachmentId,
424
+ attachment.mediaType
425
+ ]);
426
+ if (failed) return (0, react.createElement)("div", { style: styles.imageError }, "Image attachment could not be loaded.");
427
+ if (url === void 0) return (0, react.createElement)("div", { style: styles.imageToolText }, "Loading image…");
428
+ return (0, react.createElement)("img", {
429
+ src: url,
430
+ alt: attachment.name ?? "Image returned by Pi tool",
431
+ style: styles.imageFrame,
432
+ "data-pi2dsh": "tool-image"
433
+ });
434
+ }
435
+ function firstArgumentSummary(raw) {
436
+ try {
437
+ const parsed = JSON.parse(raw);
438
+ const preferred = parsed.prompt ?? parsed.description;
439
+ if (typeof preferred === "string") return preferred;
440
+ const first = Object.values(parsed).find((value) => typeof value === "string");
441
+ return typeof first === "string" ? first : "";
442
+ } catch {
443
+ return raw;
444
+ }
445
+ }
446
+ /** Browser row shared by the explicitly supported Pi image tools. */
447
+ function PiImageToolView({ toolName, block, sessionId }) {
448
+ const [expanded, setExpanded] = (0, react.useState)(true);
449
+ const settled = block.kind === "tool-result";
450
+ const argsRaw = settled ? block.call?.argsRaw ?? "" : block.argsRaw ?? "";
451
+ const content = settled && Array.isArray(block.content) ? block.content : [];
452
+ const images = content.flatMap((item) => item.type === "image" && item.attachment !== void 0 ? [item.attachment] : []);
453
+ const text = content.filter((item) => item.type === "text" && typeof item.text === "string").map((item) => item.text).join("\n");
454
+ const summary = firstArgumentSummary(argsRaw);
455
+ return (0, react.createElement)("div", {
456
+ style: styles.imageTool,
457
+ "data-pi2dsh": "image-tool-result",
458
+ "data-tool": toolName
459
+ }, (0, react.createElement)("button", {
460
+ type: "button",
461
+ style: styles.imageToolToggle,
462
+ "aria-expanded": expanded,
463
+ onClick: () => setExpanded((value) => !value)
464
+ }, (0, react.createElement)("span", { style: styles.imageToolStatus }, block.isError === true ? "●" : settled ? "●" : "◌"), (0, react.createElement)("span", null, toolName), summary === "" ? null : (0, react.createElement)("span", { style: styles.imageToolSummary }, `· ${summary}`)), !expanded ? null : (0, react.createElement)("div", { style: styles.imageToolBody }, text === "" ? null : (0, react.createElement)("div", { style: styles.imageToolText }, text), sessionId === void 0 || images.length === 0 ? null : (0, react.createElement)("div", { style: styles.imageGrid }, ...images.map((attachment) => (0, react.createElement)(AuthorizedToolImage, {
465
+ key: attachment.attachmentId,
466
+ sessionId,
467
+ attachment
468
+ })))));
469
+ }
470
+ /**
471
+ * Register the image row under exact tool names published at package mount.
472
+ * Only known image tools appear in that list, so text-only and native tools
473
+ * retain DSH's existing cards.
474
+ */
475
+ function installImageToolViews(scope) {
476
+ const installed = /* @__PURE__ */ new Set();
477
+ const start = () => {
478
+ let live = true;
479
+ const sync = async () => {
480
+ try {
481
+ const response = await fetch("/pi2dsh/image-tool-names");
482
+ if (!response.ok || !live) return;
483
+ const payload = await response.json();
484
+ if (!Array.isArray(payload.names)) return;
485
+ for (const value of payload.names) {
486
+ if (typeof value !== "string" || value === "" || installed.has(value)) continue;
487
+ installed.add(value);
488
+ scope.slots.inject("tool.call.toolview", () => scope.slots.register({
489
+ name: "tool.call.toolview",
490
+ key: value
491
+ }, PiImageToolView));
492
+ }
493
+ } catch {}
494
+ };
495
+ sync();
496
+ const timer = window.setInterval(() => {
497
+ sync();
498
+ }, POLL_MS);
499
+ return () => {
500
+ live = false;
501
+ window.clearInterval(timer);
502
+ };
503
+ };
504
+ if (scope.effect !== void 0) scope.effect(start, "pi2dsh: image tool views");
505
+ else start();
506
+ }
321
507
  /**
322
508
  * The frame-wide seat: the side-conversation panel, plus whatever packages
323
509
  * pinned frame-wide — transient title and Pi's status entries, as pills.
@@ -479,6 +665,7 @@ window.__ModuleLoader__.load({
479
665
  });
480
666
  });
481
667
  ctx.inject(["slots"], (scope) => {
668
+ installImageToolViews(scope);
482
669
  scope.slots.inject("shell.overlay", () => scope.slots.register({
483
670
  name: "shell.overlay",
484
671
  id: "pi2dsh-overlay",