pi-roundtable-drawing 0.7.2 → 0.7.3
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/CHANGELOG.md +4 -0
- package/README.md +5 -0
- package/package.json +2 -2
- package/src/cards/spread.ts +2 -1
- package/src/index.ts +1 -1
- package/src/plugin.ts +21 -2
- package/src/tools/draw-cards-tool.ts +15 -3
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,10 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.7.3] - 2026-10-03
|
|
9
|
+
|
|
10
|
+
- Add `DrawingOptions.cardPresentation` for trusted operator card headings and reversal suffixes.
|
|
11
|
+
|
|
8
12
|
## [0.7.2] - 2026-10-02
|
|
9
13
|
|
|
10
14
|
First release published by the lockstep workflow; no changes to the package.
|
package/README.md
CHANGED
|
@@ -82,8 +82,13 @@ export default {
|
|
|
82
82
|
| `deckDir` | `string` | none | A directory with one subdirectory for each deck; see [the deck directory](#the-deck-directory). Without it the plugin has no `draw_cards` tool. A directory that does not exist, holds no deck, or holds an invalid manifest stops the start with a message that names the deck and what to fix |
|
|
83
83
|
| `random` | `() => number` | `Math.random` | The random source of the map layouts and the card draws, returning a number from 0 up to, not including, 1. A seeded source makes a run reproducible: a new `seededRandom(seed)` given the same calls draws the same pictures. `seededRandom(seed)` is exported for that |
|
|
84
84
|
| `minTier` | `"owner" \| "admin" \| "member"` | `member` | The lowest tier that may use the tools. The operator's `toolTiers` setting still wins |
|
|
85
|
+
| `cardPresentation` | `CardPresentation` | package captions | Trusted operator-local headings and reversal suffixes |
|
|
85
86
|
|
|
86
87
|
The plugin is named `drawing`.
|
|
88
|
+
`cardPresentation.heading(draw, turn)` returns `{ title, subtitle }`; `draw` holds the selected `deck`, `count`, and optional `question`, and `turn` carries the host-bound speaker/channel.
|
|
89
|
+
`cardPresentation.reversedSuffix` replaces the default `" (reversed)"` on pictured reversed card names.
|
|
90
|
+
These hooks change only presentation, not card selection, model-visible arguments, tool result text, or attachment limits.
|
|
91
|
+
They are trusted configuration callbacks, never guest-supplied code.
|
|
87
92
|
|
|
88
93
|
## The tools
|
|
89
94
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-roundtable-drawing",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "Relationship maps, magic circles, sigils, sacred geometry, and card spreads drawn locally for pi-roundtable",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@biomejs/biome": "2.5.15",
|
|
50
50
|
"@types/bun": "1.4.2",
|
|
51
|
-
"pi-roundtable": "0.7.
|
|
51
|
+
"pi-roundtable": "0.7.3",
|
|
52
52
|
"typescript": "7.0.2"
|
|
53
53
|
}
|
|
54
54
|
}
|
package/src/cards/spread.ts
CHANGED
|
@@ -112,6 +112,7 @@ export async function renderSpread(
|
|
|
112
112
|
cards: readonly DrawnCard[],
|
|
113
113
|
positions: readonly SpreadPosition[],
|
|
114
114
|
heading: { title: string; subtitle: string },
|
|
115
|
+
reversedSuffix = " (reversed)",
|
|
115
116
|
): Promise<Uint8Array> {
|
|
116
117
|
checkSpread(positions, cards.length);
|
|
117
118
|
ensureFont();
|
|
@@ -225,7 +226,7 @@ export async function renderSpread(
|
|
|
225
226
|
|
|
226
227
|
ctx.fillStyle = card.reversed ? PALETTE.accentLight : PALETTE.text;
|
|
227
228
|
ctx.font = font(width < 150 ? 12 : 15);
|
|
228
|
-
const name = card.reversed ? `${card.name}
|
|
229
|
+
const name = card.reversed ? `${card.name}${reversedSuffix}` : card.name;
|
|
229
230
|
ctx.fillText(fitText(ctx, name, width), x + width / 2, y + height + 8);
|
|
230
231
|
}
|
|
231
232
|
return new Uint8Array(canvas.toBuffer("image/png"));
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { Card, Deck } from "./cards/deck.ts";
|
|
2
|
-
export type { DrawingOptions } from "./plugin.ts";
|
|
2
|
+
export type { CardPresentation, DrawingOptions } from "./plugin.ts";
|
|
3
3
|
export { drawing } from "./plugin.ts";
|
|
4
4
|
export type { Random } from "./random.ts";
|
|
5
5
|
export { seededRandom } from "./random.ts";
|
package/src/plugin.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
definePlugin,
|
|
3
|
+
PluginError,
|
|
4
|
+
type Tier,
|
|
5
|
+
type ToolTurn,
|
|
6
|
+
} from "pi-roundtable";
|
|
2
7
|
import { type Deck, DeckError, loadDecks } from "./cards/deck.ts";
|
|
3
8
|
import type { Random } from "./random.ts";
|
|
4
9
|
import { drawCardsTool } from "./tools/draw-cards-tool.ts";
|
|
@@ -10,6 +15,16 @@ import {
|
|
|
10
15
|
} from "./tools/magic-tools.ts";
|
|
11
16
|
import { relationshipMapTool } from "./tools/relationship-map-tool.ts";
|
|
12
17
|
|
|
18
|
+
export interface CardPresentation {
|
|
19
|
+
/** Trusted host presentation; never part of the model's tool arguments. */
|
|
20
|
+
heading?: (
|
|
21
|
+
draw: { deck: Deck; count: number; question?: string },
|
|
22
|
+
turn: ToolTurn,
|
|
23
|
+
) => { title: string; subtitle: string };
|
|
24
|
+
/** Appended to reversed card names on the picture; default " (reversed)". */
|
|
25
|
+
reversedSuffix?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
13
28
|
export interface DrawingOptions {
|
|
14
29
|
/**
|
|
15
30
|
* A directory with one subdirectory for each deck, each holding a `deck.json` and the card
|
|
@@ -21,6 +36,8 @@ export interface DrawingOptions {
|
|
|
21
36
|
random?: Random;
|
|
22
37
|
/** The lowest tier that may use the tools; default `member`. */
|
|
23
38
|
minTier?: Tier;
|
|
39
|
+
/** Operator-local captions and reversal wording; default package presentation. */
|
|
40
|
+
cardPresentation?: CardPresentation;
|
|
24
41
|
}
|
|
25
42
|
|
|
26
43
|
function readDecks(deckDir: string): Deck[] {
|
|
@@ -53,7 +70,9 @@ export function drawing(options: DrawingOptions = {}) {
|
|
|
53
70
|
magicCircleTool(env),
|
|
54
71
|
sigilTool(env),
|
|
55
72
|
sacredGeometryTool(env),
|
|
56
|
-
...(decks.length > 0
|
|
73
|
+
...(decks.length > 0
|
|
74
|
+
? [drawCardsTool(decks, env, random, options.cardPresentation)]
|
|
75
|
+
: []),
|
|
57
76
|
],
|
|
58
77
|
};
|
|
59
78
|
},
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type SpreadPosition,
|
|
11
11
|
} from "../cards/spread.ts";
|
|
12
12
|
import { DrawingError } from "../errors.ts";
|
|
13
|
+
import type { CardPresentation } from "../plugin.ts";
|
|
13
14
|
import type { Random } from "../random.ts";
|
|
14
15
|
import {
|
|
15
16
|
type ImageToolEnv,
|
|
@@ -32,6 +33,7 @@ export function drawCardsTool(
|
|
|
32
33
|
decks: readonly Deck[],
|
|
33
34
|
env: ImageToolEnv,
|
|
34
35
|
random: Random,
|
|
36
|
+
presentation: CardPresentation = {},
|
|
35
37
|
) {
|
|
36
38
|
const [first, ...rest] = decks;
|
|
37
39
|
if (!first) throw new DrawingError("draw_cards needs at least one deck.");
|
|
@@ -81,7 +83,7 @@ export function drawCardsTool(
|
|
|
81
83
|
Type.String({ description: "The question, shown on the picture." }),
|
|
82
84
|
),
|
|
83
85
|
}),
|
|
84
|
-
draw: async (args) => {
|
|
86
|
+
draw: async (args, turn) => {
|
|
85
87
|
const deck = decks.find((candidate) => candidate.id === args.deck);
|
|
86
88
|
if (!deck)
|
|
87
89
|
throw new DrawingError(
|
|
@@ -99,12 +101,22 @@ export function drawCardsTool(
|
|
|
99
101
|
allowReversed: args.allow_reversed,
|
|
100
102
|
random,
|
|
101
103
|
});
|
|
102
|
-
const
|
|
104
|
+
const heading = presentation.heading?.(
|
|
105
|
+
{ deck, count: cards.length, question: args.question },
|
|
106
|
+
turn,
|
|
107
|
+
) ?? {
|
|
103
108
|
title: deck.name,
|
|
104
109
|
subtitle:
|
|
105
110
|
args.question ??
|
|
106
111
|
`${cards.length} card${cards.length === 1 ? "" : "s"}`,
|
|
107
|
-
}
|
|
112
|
+
};
|
|
113
|
+
const image = await renderSpread(
|
|
114
|
+
deck,
|
|
115
|
+
cards,
|
|
116
|
+
positions,
|
|
117
|
+
heading,
|
|
118
|
+
presentation.reversedSuffix,
|
|
119
|
+
);
|
|
108
120
|
const lines = cards.map((card, i) => {
|
|
109
121
|
const label = positions[i]?.label ? `${positions[i]?.label}: ` : "";
|
|
110
122
|
return `${i + 1}. ${label}${card.name}${card.reversed ? " (reversed)" : ""} [id: ${card.id}]`;
|