@jsm-mit/sultana-agent-tools-package 0.2.0

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.
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Everything the tools are allowed to do to a salon, in plain JSON.
3
+ *
4
+ * Two reasons this port exists instead of the tools calling the canister wrapper directly:
5
+ * the tools become testable without a replica, and no `bigint`, `Principal` or candid variant can
6
+ * leak into a tool result — a model has to be able to read every value it is shown.
7
+ *
8
+ * The port is **salon-scoped**: the implementation carries the salon id, so no method takes one.
9
+ * That is what makes it impossible for a model to address another salon.
10
+ */
11
+ /**
12
+ * Whose view of the salon a read returns. `"owner"` is the whole salon — switched-off services and
13
+ * draft promos included — and needs the owner's identity. `"public"` is what a visitor sees: ACTIVE
14
+ * services and ACTIVE promos only, readable without any identity.
15
+ */
16
+ export type SalonAccess = "owner" | "public";
17
+ export interface ServiceView {
18
+ id: string;
19
+ name: string;
20
+ /** Whole zloty — the canister stores an integer and so do we. */
21
+ pricePln: number;
22
+ /** Always a multiple of 5. */
23
+ durationMinutes: number;
24
+ active: boolean;
25
+ serviceTypeIds: string[];
26
+ /** Worker principals as text. */
27
+ workerIds: string[];
28
+ }
29
+ /** The full set of fields `updateSalonService` replaces. Every write goes through this shape so a
30
+ * partial edit has to be merged explicitly rather than by accident. */
31
+ export interface ServiceWriteInput {
32
+ name: string;
33
+ pricePln: number;
34
+ durationMinutes: number;
35
+ active: boolean;
36
+ serviceTypeIds: string[];
37
+ workerIds: string[];
38
+ }
39
+ export interface WorkerView {
40
+ id: string;
41
+ name: string;
42
+ /** False while the worker has not claimed their account with the code yet. */
43
+ linked: boolean;
44
+ }
45
+ export interface ServiceTypeView {
46
+ id: string;
47
+ /** Label in the requested language. */
48
+ label: string;
49
+ category: string | null;
50
+ }
51
+ export interface SalonCorePort extends SalonSchedulePort, SalonPromoPort {
52
+ listServices(): Promise<ServiceView[]>;
53
+ addService(input: ServiceWriteInput): Promise<string>;
54
+ updateService(serviceId: string, input: ServiceWriteInput): Promise<void>;
55
+ removeService(serviceId: string): Promise<void>;
56
+ listWorkers(): Promise<WorkerView[]>;
57
+ /** Catalog search — the same matcher both frontends use, so the agent and the UI agree on
58
+ * what "strzyżenie" means. An empty query returns the whole catalog. */
59
+ findServiceTypes(query: string): Promise<ServiceTypeView[]>;
60
+ }
61
+ /** A window of the day, `"HH:mm"` on both ends. The canister wrapper speaks exactly this shape. */
62
+ export interface TimeRange {
63
+ startTime: string;
64
+ endTime: string;
65
+ }
66
+ /**
67
+ * Scheduling, which has one trap worth naming: the **weekly template stores working hours**, while
68
+ * a **daily override stores busy hours**. The canister models them that way and the wrapper passes
69
+ * it straight through, so the port keeps the two words apart rather than calling both "hours".
70
+ */
71
+ export interface SalonSchedulePort {
72
+ /** Working windows for one weekday. 0 = Monday … 6 = Sunday. */
73
+ getWeeklyHours(workerId: string, day: number): Promise<TimeRange[]>;
74
+ setWeeklyHours(workerId: string, day: number, ranges: TimeRange[]): Promise<void>;
75
+ /** Busy windows overriding the template for one date (`"YYYY-MM-DD"`). */
76
+ getDailyBusy(workerId: string, date: string): Promise<TimeRange[]>;
77
+ setDailyBusy(workerId: string, date: string, ranges: TimeRange[]): Promise<void>;
78
+ /** Marks the whole date busy. */
79
+ setDayOff(workerId: string, date: string): Promise<void>;
80
+ /** Drops the override, so the weekly template applies again. */
81
+ clearDailyOverride(workerId: string, date: string): Promise<void>;
82
+ }
83
+ export interface MediaView {
84
+ assetId: string;
85
+ name: string;
86
+ kind: "image" | "video" | "audio";
87
+ }
88
+ export interface PromoView {
89
+ id: string;
90
+ name: string;
91
+ active: boolean;
92
+ assetId: string;
93
+ textLines: string[];
94
+ chips: string[];
95
+ buttonLabel?: string;
96
+ discountCode?: string;
97
+ /** The service a tap leads to; absent = the salon itself. */
98
+ targetServiceId?: string;
99
+ /** A promo rendered over a music track. The tools never build one — they only carry it
100
+ * through an edit, because the canister replaces the whole record. */
101
+ hasMusic: boolean;
102
+ /** The music record itself, opaque to the tools and passed back verbatim on an edit. */
103
+ music?: unknown;
104
+ }
105
+ /** Everything `updatePromo` replaces. `music` is opaque here on purpose: it is read from the
106
+ * current promo and written back untouched, never composed by a tool. */
107
+ export interface PromoWriteInput {
108
+ name: string;
109
+ assetId: string;
110
+ textLines: string[];
111
+ chips: string[];
112
+ buttonLabel?: string;
113
+ discountCode?: string;
114
+ targetServiceId?: string;
115
+ music?: unknown;
116
+ }
117
+ export interface DiscountCodeView {
118
+ code: string;
119
+ /** Either `{percent}` or `{amountPln}` — exactly one is set. */
120
+ percent?: number;
121
+ amountPln?: number;
122
+ /** The service the code is limited to; absent = the whole salon. */
123
+ scopeServiceId?: string;
124
+ }
125
+ export interface DiscountCodeInput {
126
+ code: string;
127
+ percent?: number;
128
+ amountPln?: number;
129
+ scopeServiceId?: string;
130
+ }
131
+ /** The promo library and the discount codes it can broadcast. */
132
+ export interface SalonPromoPort {
133
+ /** Ready images and videos of the salon's library — what a promo can be built on. */
134
+ listMedia(): Promise<MediaView[]>;
135
+ listPromos(): Promise<PromoView[]>;
136
+ addPromo(input: PromoWriteInput): Promise<string>;
137
+ updatePromo(promoId: string, input: PromoWriteInput): Promise<void>;
138
+ setPromoActive(promoId: string, active: boolean): Promise<void>;
139
+ removePromo(promoId: string): Promise<void>;
140
+ listDiscountCodes(): Promise<DiscountCodeView[]>;
141
+ addDiscountCode(input: DiscountCodeInput): Promise<void>;
142
+ removeDiscountCode(code: string): Promise<void>;
143
+ }
144
+ //# sourceMappingURL=salon-core-port.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"salon-core-port.d.ts","sourceRoot":"","sources":["../src/salon-core-port.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE7C,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,iCAAiC;IACjC,SAAS,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;uEACuE;AACvE,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,MAAM,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,aAAc,SAAQ,iBAAiB,EAAE,cAAc;IACpE,YAAY,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACvC,UAAU,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACtD,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhD,WAAW,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAErC;4EACwE;IACxE,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;CAC/D;AAED,mGAAmG;AACnG,MAAM,WAAW,SAAS;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAC9B,gEAAgE;IAChE,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACpE,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAElF,0EAA0E;IAC1E,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACnE,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjF,iCAAiC;IACjC,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,gEAAgE;IAChE,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrE;AAED,MAAM,WAAW,SAAS;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;CACrC;AAED,MAAM,WAAW,SAAS;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;0EACsE;IACtE,QAAQ,EAAE,OAAO,CAAC;IAClB,wFAAwF;IACxF,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;yEACyE;AACzE,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,iEAAiE;AACjE,MAAM,WAAW,cAAc;IAC3B,qFAAqF;IACrF,SAAS,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAElC,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5C,iBAAiB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACjD,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Everything the tools are allowed to do to a salon, in plain JSON.
3
+ *
4
+ * Two reasons this port exists instead of the tools calling the canister wrapper directly:
5
+ * the tools become testable without a replica, and no `bigint`, `Principal` or candid variant can
6
+ * leak into a tool result — a model has to be able to read every value it is shown.
7
+ *
8
+ * The port is **salon-scoped**: the implementation carries the salon id, so no method takes one.
9
+ * That is what makes it impossible for a model to address another salon.
10
+ */
11
+ export {};
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Argument reading for tool calls. A model sends whatever it likes — a number as a string, a
3
+ * single value where a list belongs, `null` for "unset" — so every read is forgiving about the
4
+ * shape and strict about the value.
5
+ *
6
+ * Each reader throws `ArgumentError`; tool bodies turn that into a `status: "error"` result.
7
+ */
8
+ export declare class ArgumentError extends Error {
9
+ }
10
+ export declare function readOptionalString(args: Record<string, unknown>, key: string): string | undefined;
11
+ export declare function readString(args: Record<string, unknown>, key: string): string;
12
+ export declare function readOptionalNumber(args: Record<string, unknown>, key: string): number | undefined;
13
+ export declare function readNumber(args: Record<string, unknown>, key: string): number;
14
+ /** Absent means "not confirmed" — never "assume yes". */
15
+ export declare function readBoolean(args: Record<string, unknown>, key: string): boolean;
16
+ export declare function readOptionalStringArray(args: Record<string, unknown>, key: string): string[] | undefined;
17
+ export interface NormalizedNumber {
18
+ value: number;
19
+ /** Set when the value had to be adjusted — the agent must tell the owner about it. */
20
+ note?: string;
21
+ }
22
+ /** The canister stores a price as an integer of whole zloty. */
23
+ export declare function normalizePrice(pricePln: number): NormalizedNumber;
24
+ /** Availability is a grid of 5-minute slots, so a duration that is not a multiple of 5 cannot be
25
+ * booked. Rounding up rather than down — a service that overruns its slot is worse than one that
26
+ * ends early. */
27
+ export declare function normalizeDuration(durationMinutes: number): NormalizedNumber;
28
+ /** Confirmation phrases are compared the way a person types them: case and spacing do not count. */
29
+ export declare function phrasesMatch(typed: string, expected: string): boolean;
30
+ //# sourceMappingURL=args.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/tools/args.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,qBAAa,aAAc,SAAQ,KAAK;CAAG;AAE3C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOjG;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAI7E;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQjG;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAI7E;AAED,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAK/E;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAgBxG;AAED,MAAM,WAAW,gBAAgB;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,sFAAsF;IACtF,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAOjE;AAED;;iBAEiB;AACjB,wBAAgB,iBAAiB,CAAC,eAAe,EAAE,MAAM,GAAG,gBAAgB,CAO3E;AAED,oGAAoG;AACpG,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGrE"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Argument reading for tool calls. A model sends whatever it likes — a number as a string, a
3
+ * single value where a list belongs, `null` for "unset" — so every read is forgiving about the
4
+ * shape and strict about the value.
5
+ *
6
+ * Each reader throws `ArgumentError`; tool bodies turn that into a `status: "error"` result.
7
+ */
8
+ export class ArgumentError extends Error {
9
+ }
10
+ export function readOptionalString(args, key) {
11
+ const value = args[key];
12
+ if (value === undefined || value === null || value === "")
13
+ return undefined;
14
+ if (typeof value !== "string")
15
+ throw new ArgumentError(`Pole "${key}" musi być tekstem.`);
16
+ const trimmed = value.trim();
17
+ return trimmed === "" ? undefined : trimmed;
18
+ }
19
+ export function readString(args, key) {
20
+ const value = readOptionalString(args, key);
21
+ if (value === undefined)
22
+ throw new ArgumentError(`Brakuje pola "${key}".`);
23
+ return value;
24
+ }
25
+ export function readOptionalNumber(args, key) {
26
+ const value = args[key];
27
+ if (value === undefined || value === null || value === "")
28
+ return undefined;
29
+ const parsed = typeof value === "number" ? value : Number(String(value).replace(",", "."));
30
+ if (!Number.isFinite(parsed))
31
+ throw new ArgumentError(`Pole "${key}" musi być liczbą.`);
32
+ return parsed;
33
+ }
34
+ export function readNumber(args, key) {
35
+ const value = readOptionalNumber(args, key);
36
+ if (value === undefined)
37
+ throw new ArgumentError(`Brakuje pola "${key}".`);
38
+ return value;
39
+ }
40
+ /** Absent means "not confirmed" — never "assume yes". */
41
+ export function readBoolean(args, key) {
42
+ const value = args[key];
43
+ if (typeof value === "boolean")
44
+ return value;
45
+ if (typeof value === "string")
46
+ return value.trim().toLowerCase() === "true";
47
+ return false;
48
+ }
49
+ export function readOptionalStringArray(args, key) {
50
+ const value = args[key];
51
+ if (value === undefined || value === null)
52
+ return undefined;
53
+ // A model that has exactly one id often sends it bare instead of in a list.
54
+ const list = Array.isArray(value) ? value : [value];
55
+ const items = [];
56
+ for (const entry of list) {
57
+ if (typeof entry !== "string")
58
+ throw new ArgumentError(`Pole "${key}" musi być listą tekstów.`);
59
+ const trimmed = entry.trim();
60
+ if (trimmed !== "")
61
+ items.push(trimmed);
62
+ }
63
+ return items;
64
+ }
65
+ /** The canister stores a price as an integer of whole zloty. */
66
+ export function normalizePrice(pricePln) {
67
+ if (pricePln < 0)
68
+ throw new ArgumentError("Cena nie może być ujemna.");
69
+ const rounded = Math.round(pricePln);
70
+ if (rounded === pricePln)
71
+ return { value: rounded };
72
+ return { value: rounded, note: `cenę ${pricePln} zł zaokrąglono do ${rounded} zł` };
73
+ }
74
+ /** Availability is a grid of 5-minute slots, so a duration that is not a multiple of 5 cannot be
75
+ * booked. Rounding up rather than down — a service that overruns its slot is worse than one that
76
+ * ends early. */
77
+ export function normalizeDuration(durationMinutes) {
78
+ if (durationMinutes < 5)
79
+ throw new ArgumentError("Czas trwania musi wynosić co najmniej 5 minut.");
80
+ const rounded = Math.ceil(durationMinutes / 5) * 5;
81
+ if (rounded === durationMinutes)
82
+ return { value: rounded };
83
+ return { value: rounded, note: `czas ${durationMinutes} min zaokrąglono w górę do ${rounded} min` };
84
+ }
85
+ /** Confirmation phrases are compared the way a person types them: case and spacing do not count. */
86
+ export function phrasesMatch(typed, expected) {
87
+ const fold = (text) => text.trim().toLowerCase().replace(/\s+/g, " ");
88
+ return fold(typed) === fold(expected);
89
+ }
@@ -0,0 +1,7 @@
1
+ import type { SalonAccess, SalonCorePort } from "../salon-core-port.js";
2
+ import { type AgentTool } from "../types.js";
3
+ export declare function createPromoTools(port: SalonCorePort): AgentTool[];
4
+ /** `access` must match the port: `"public"` only for a port read anonymously, because the canister
5
+ * gives the salon's owner the whole library whatever the port calls. */
6
+ export declare function listPromosTool(port: SalonCorePort, access?: SalonAccess): AgentTool;
7
+ //# sourceMappingURL=promos.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promos.d.ts","sourceRoot":"","sources":["../../src/tools/promos.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA8B,WAAW,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACpG,OAAO,EAA8B,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAqBzE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,EAAE,CAYjE;AA2CD;wEACwE;AACxE,wBAAgB,cAAc,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM,GAAE,WAAqB,GAAG,SAAS,CAmB5F"}