@things-factory/ai-dashboard 10.1.213 → 10.1.215

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 (73) hide show
  1. package/client/components/card-dialogs.ts +24 -1
  2. package/client/components/dashboard-card.ts +24 -70
  3. package/client/index.ts +2 -0
  4. package/client/pages/my-dashboard-page.ts +6 -5
  5. package/client/utils/card-api.ts +3 -2
  6. package/client/utils/card-words.ts +11 -0
  7. package/client/utils/examples.ts +15 -0
  8. package/dist-client/components/card-dialogs.js +22 -1
  9. package/dist-client/components/card-dialogs.js.map +1 -1
  10. package/dist-client/components/dashboard-card.d.ts +6 -5
  11. package/dist-client/components/dashboard-card.js +23 -73
  12. package/dist-client/components/dashboard-card.js.map +1 -1
  13. package/dist-client/index.d.ts +1 -0
  14. package/dist-client/index.js +2 -0
  15. package/dist-client/index.js.map +1 -1
  16. package/dist-client/pages/my-dashboard-page.js +6 -5
  17. package/dist-client/pages/my-dashboard-page.js.map +1 -1
  18. package/dist-client/tsconfig.tsbuildinfo +1 -1
  19. package/dist-client/utils/card-api.d.ts +6 -1
  20. package/dist-client/utils/card-api.js +1 -1
  21. package/dist-client/utils/card-api.js.map +1 -1
  22. package/dist-client/utils/card-words.d.ts +14 -0
  23. package/dist-client/utils/card-words.js +9 -0
  24. package/dist-client/utils/card-words.js.map +1 -1
  25. package/dist-client/utils/examples.d.ts +3 -0
  26. package/dist-client/utils/examples.js +14 -0
  27. package/dist-client/utils/examples.js.map +1 -0
  28. package/dist-server/service/card/card-access.d.ts +8 -2
  29. package/dist-server/service/card/card-access.js +9 -3
  30. package/dist-server/service/card/card-access.js.map +1 -1
  31. package/dist-server/service/card/card-definition.d.ts +42 -6
  32. package/dist-server/service/card/card-definition.js +172 -18
  33. package/dist-server/service/card/card-definition.js.map +1 -1
  34. package/dist-server/service/card/card-names.d.ts +5 -0
  35. package/dist-server/service/card/card-names.js +6 -1
  36. package/dist-server/service/card/card-names.js.map +1 -1
  37. package/dist-server/service/card/card-proposal.d.ts +6 -0
  38. package/dist-server/service/card/card-proposal.js +9 -0
  39. package/dist-server/service/card/card-proposal.js.map +1 -1
  40. package/dist-server/service/card/card-resolver.js +24 -5
  41. package/dist-server/service/card/card-resolver.js.map +1 -1
  42. package/dist-server/service/card/card-run.js +5 -1
  43. package/dist-server/service/card/card-run.js.map +1 -1
  44. package/dist-server/service/card/card-tool.d.ts +66 -8
  45. package/dist-server/service/card/card-tool.js +88 -17
  46. package/dist-server/service/card/card-tool.js.map +1 -1
  47. package/dist-server/service/card/card-types.d.ts +1 -0
  48. package/dist-server/service/card/card-types.js +8 -4
  49. package/dist-server/service/card/card-types.js.map +1 -1
  50. package/dist-server/service/card/dashboard-card.d.ts +2 -0
  51. package/dist-server/service/card/dashboard-card.js +5 -3
  52. package/dist-server/service/card/dashboard-card.js.map +1 -1
  53. package/dist-server/tsconfig.tsbuildinfo +1 -1
  54. package/package.json +5 -5
  55. package/server/service/card/card-access.test.ts +62 -7
  56. package/server/service/card/card-access.ts +12 -5
  57. package/server/service/card/card-definition.ts +182 -18
  58. package/server/service/card/card-intent.test.ts +250 -0
  59. package/server/service/card/card-names.ts +5 -0
  60. package/server/service/card/card-proposal.ts +10 -1
  61. package/server/service/card/card-resolver.ts +26 -8
  62. package/server/service/card/card-run.ts +5 -1
  63. package/server/service/card/card-tool.ts +91 -20
  64. package/server/service/card/card-types.ts +7 -4
  65. package/server/service/card/dashboard-card.ts +5 -3
  66. package/test/card-menu.test.ts +34 -0
  67. package/test/translations.test.ts +1 -1
  68. package/translations/en.json +3 -3
  69. package/translations/es.json +3 -3
  70. package/translations/ja.json +3 -3
  71. package/translations/ko.json +3 -3
  72. package/translations/ms.json +3 -3
  73. package/translations/zh.json +3 -3
@@ -2,8 +2,18 @@ import { type ToolCategory } from '@things-factory/ai-client-base';
2
2
  import { type CardDefinition } from './card-definition.js';
3
3
  import { CARD_CATEGORY, CARD_TOOL, DASHBOARD_PAGE } from './card-names.js';
4
4
  export { CARD_CATEGORY, CARD_TOOL, DASHBOARD_PAGE };
5
- /** The reads a card may name - list read targets, and detail reads with declared lists (`key/list`). */
6
- export declare function cardSources(): string[];
5
+ /** The reads a card may name - each list read target and each detail read's list, with the tool the model knows it by. */
6
+ export declare function cardSources(): {
7
+ read: string;
8
+ list?: string;
9
+ tool: string;
10
+ mine?: true;
11
+ }[];
12
+ /**
13
+ * The read a model named - its key, or the name of the tool it reads it with (`queryPlantJobOrder` is `plant.job-order`):
14
+ * the model knows reads by their tools, and named the tool as the card's source (2026-10-25, plant).
15
+ */
16
+ export declare function readKeyOf(given: unknown): unknown;
7
17
  /** A saved card as a change needs it - whose it is and its version. */
8
18
  export type CardOf = (id: string) => Promise<{
9
19
  ownerId?: string;
@@ -16,11 +26,17 @@ export declare function proposeDashboardCard(args: any, context: any, deps?: {
16
26
  cardOf?: CardOf;
17
27
  }): Promise<{
18
28
  message: string;
19
- sources?: string[];
29
+ sources?: {
30
+ read: string;
31
+ list?: string;
32
+ tool: string;
33
+ mine?: true;
34
+ }[];
20
35
  rejected: boolean;
21
36
  error: string;
22
37
  issues?: undefined;
23
38
  source?: undefined;
39
+ cardId?: undefined;
24
40
  current?: undefined;
25
41
  read?: undefined;
26
42
  label?: undefined;
@@ -35,11 +51,12 @@ export declare function proposeDashboardCard(args: any, context: any, deps?: {
35
51
  issues: import("./card-definition.js").CardIssue[];
36
52
  source: {
37
53
  columnsAfterGroupBy?: string[];
38
- description: string;
39
54
  conditions: {
40
55
  description?: string;
41
56
  values?: string[];
42
57
  required?: boolean;
58
+ takes?: string;
59
+ format?: string;
43
60
  name: string;
44
61
  type: string;
45
62
  }[];
@@ -48,10 +65,28 @@ export declare function proposeDashboardCard(args: any, context: any, deps?: {
48
65
  name: string;
49
66
  type: "string" | "number" | "date";
50
67
  }[];
68
+ mine?: string;
69
+ description: string;
51
70
  list?: string;
52
71
  read: string;
53
72
  };
54
73
  message: string;
74
+ cardId?: undefined;
75
+ current?: undefined;
76
+ read?: undefined;
77
+ label?: undefined;
78
+ use?: undefined;
79
+ proposed?: undefined;
80
+ kind?: undefined;
81
+ icon?: undefined;
82
+ card?: undefined;
83
+ } | {
84
+ rejected: boolean;
85
+ error: string;
86
+ cardId: any;
87
+ message: string;
88
+ issues?: undefined;
89
+ source?: undefined;
55
90
  current?: undefined;
56
91
  read?: undefined;
57
92
  label?: undefined;
@@ -67,6 +102,7 @@ export declare function proposeDashboardCard(args: any, context: any, deps?: {
67
102
  message: string;
68
103
  issues?: undefined;
69
104
  source?: undefined;
105
+ cardId?: undefined;
70
106
  read?: undefined;
71
107
  label?: undefined;
72
108
  use?: undefined;
@@ -77,11 +113,12 @@ export declare function proposeDashboardCard(args: any, context: any, deps?: {
77
113
  } | {
78
114
  source: {
79
115
  columnsAfterGroupBy?: string[];
80
- description: string;
81
116
  conditions: {
82
117
  description?: string;
83
118
  values?: string[];
84
119
  required?: boolean;
120
+ takes?: string;
121
+ format?: string;
85
122
  name: string;
86
123
  type: string;
87
124
  }[];
@@ -90,6 +127,8 @@ export declare function proposeDashboardCard(args: any, context: any, deps?: {
90
127
  name: string;
91
128
  type: "string" | "number" | "date";
92
129
  }[];
130
+ mine?: string;
131
+ description: string;
93
132
  list?: string;
94
133
  read: string;
95
134
  };
@@ -98,6 +137,7 @@ export declare function proposeDashboardCard(args: any, context: any, deps?: {
98
137
  rejected: boolean;
99
138
  error: string;
100
139
  issues?: undefined;
140
+ cardId?: undefined;
101
141
  current?: undefined;
102
142
  read?: undefined;
103
143
  label?: undefined;
@@ -112,11 +152,12 @@ export declare function proposeDashboardCard(args: any, context: any, deps?: {
112
152
  read: number;
113
153
  source: {
114
154
  columnsAfterGroupBy?: string[];
115
- description: string;
116
155
  conditions: {
117
156
  description?: string;
118
157
  values?: string[];
119
158
  required?: boolean;
159
+ takes?: string;
160
+ format?: string;
120
161
  name: string;
121
162
  type: string;
122
163
  }[];
@@ -125,11 +166,14 @@ export declare function proposeDashboardCard(args: any, context: any, deps?: {
125
166
  name: string;
126
167
  type: "string" | "number" | "date";
127
168
  }[];
169
+ mine?: string;
170
+ description: string;
128
171
  list?: string;
129
172
  read: string;
130
173
  };
131
174
  message: string;
132
175
  issues?: undefined;
176
+ cardId?: undefined;
133
177
  current?: undefined;
134
178
  label?: undefined;
135
179
  use?: undefined;
@@ -144,11 +188,12 @@ export declare function proposeDashboardCard(args: any, context: any, deps?: {
144
188
  use: string;
145
189
  source: {
146
190
  columnsAfterGroupBy?: string[];
147
- description: string;
148
191
  conditions: {
149
192
  description?: string;
150
193
  values?: string[];
151
194
  required?: boolean;
195
+ takes?: string;
196
+ format?: string;
152
197
  name: string;
153
198
  type: string;
154
199
  }[];
@@ -157,11 +202,14 @@ export declare function proposeDashboardCard(args: any, context: any, deps?: {
157
202
  name: string;
158
203
  type: "string" | "number" | "date";
159
204
  }[];
205
+ mine?: string;
206
+ description: string;
160
207
  list?: string;
161
208
  read: string;
162
209
  };
163
210
  message: string;
164
211
  issues?: undefined;
212
+ cardId?: undefined;
165
213
  current?: undefined;
166
214
  read?: undefined;
167
215
  proposed?: undefined;
@@ -174,7 +222,7 @@ export declare function proposeDashboardCard(args: any, context: any, deps?: {
174
222
  icon: string;
175
223
  label: any;
176
224
  card: {
177
- cardId?: any;
225
+ cardId?: string;
178
226
  baseVersion?: number;
179
227
  definition: CardDefinition;
180
228
  description?: any;
@@ -185,6 +233,7 @@ export declare function proposeDashboardCard(args: any, context: any, deps?: {
185
233
  error?: undefined;
186
234
  issues?: undefined;
187
235
  source?: undefined;
236
+ cardId?: undefined;
188
237
  current?: undefined;
189
238
  read?: undefined;
190
239
  use?: undefined;
@@ -205,6 +254,15 @@ export declare function readDashboardCard(args: any, context: any, cardOf?: (id:
205
254
  version?: undefined;
206
255
  access?: undefined;
207
256
  definition?: undefined;
257
+ } | {
258
+ rejected: boolean;
259
+ error: string;
260
+ id: any;
261
+ message: string;
262
+ name?: undefined;
263
+ version?: undefined;
264
+ access?: undefined;
265
+ definition?: undefined;
208
266
  } | {
209
267
  id: any;
210
268
  name: any;
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.cardCategory = exports.DASHBOARD_PAGE = exports.CARD_TOOL = exports.CARD_CATEGORY = void 0;
37
37
  exports.cardSources = cardSources;
38
+ exports.readKeyOf = readKeyOf;
38
39
  exports.proposeDashboardCard = proposeDashboardCard;
39
40
  exports.readDashboardCard = readDashboardCard;
40
41
  /*
@@ -54,6 +55,7 @@ const card_names_js_1 = require("./card-names.js");
54
55
  Object.defineProperty(exports, "CARD_CATEGORY", { enumerable: true, get: function () { return card_names_js_1.CARD_CATEGORY; } });
55
56
  Object.defineProperty(exports, "CARD_TOOL", { enumerable: true, get: function () { return card_names_js_1.CARD_TOOL; } });
56
57
  Object.defineProperty(exports, "DASHBOARD_PAGE", { enumerable: true, get: function () { return card_names_js_1.DASHBOARD_PAGE; } });
58
+ const card_proposal_js_1 = require("./card-proposal.js");
57
59
  /** What a read offers a card - for a refusal the model fixes the definition from. */
58
60
  function sourceSheet(source, groupBy) {
59
61
  return {
@@ -61,18 +63,35 @@ function sourceSheet(source, groupBy) {
61
63
  ...(source.list ? { list: source.list.key } : {}),
62
64
  /* What the rows are - a state as of today or a ledger over time - decides whether a period is a filter at all. */
63
65
  description: source.description,
64
- conditions: source.conditions.map(one => ({ name: one.name, type: one.type, ...(one.required ? { required: true } : {}), ...(one.values ? { values: one.values } : {}), ...(one.description ? { description: one.description } : {}) })),
66
+ ...(source.mine ? { mine: 'the rows are the viewer\'s own, whoever looks - no filter on a person' } : {}),
67
+ conditions: source.conditions.map(one => ({ name: one.name, type: one.type, ...(one.format ? { format: 'YYYY-MM' } : {}), ...(one.many ? { takes: 'one value or a list' } : {}), ...(one.required ? { required: true } : {}), ...(one.values ? { values: one.values } : {}), ...(one.description ? { description: one.description } : {}) })),
65
68
  columns: source.columns.map(one => ({ name: one.name, type: one.type, ...(one.currency ? { currency: one.currency } : {}) })),
66
69
  ...(groupBy ? { columnsAfterGroupBy: [...(0, card_run_js_1.shapedColumnNames)(source, { groupBy }).keys()] } : {})
67
70
  };
68
71
  }
69
- /** The reads a card may name - list read targets, and detail reads with declared lists (`key/list`). */
72
+ /** The reads a card may name - each list read target and each detail read's list, with the tool the model knows it by. */
70
73
  function cardSources() {
71
74
  return [
72
- ...(0, ai_assistant_1.readTargetKeys)(),
73
- ...(0, ai_assistant_1.detailReadKeys)().flatMap(key => ((0, ai_assistant_1.detailReadOf)(key)?.lists ?? []).map(list => `${key}/${list.key}`))
75
+ ...(0, ai_assistant_1.readTargetKeys)().map(key => ({ read: key, tool: (0, ai_assistant_1.queryToolName)(key), ...((0, ai_assistant_1.readTargetOf)(key)?.mine ? { mine: true } : {}) })),
76
+ ...(0, ai_assistant_1.detailReadKeys)().flatMap(key => ((0, ai_assistant_1.detailReadOf)(key)?.lists ?? []).map(list => ({ read: key, list: list.key, tool: (0, ai_assistant_1.detailToolName)(key), ...((0, ai_assistant_1.detailReadOf)(key)?.mine ? { mine: true } : {}) })))
74
77
  ];
75
78
  }
79
+ /**
80
+ * The read a model named - its key, or the name of the tool it reads it with (`queryPlantJobOrder` is `plant.job-order`):
81
+ * the model knows reads by their tools, and named the tool as the card's source (2026-10-25, plant).
82
+ */
83
+ function readKeyOf(given) {
84
+ if (typeof given !== 'string' || (0, ai_assistant_1.readTargetOf)(given) || (0, ai_assistant_1.detailReadOf)(given))
85
+ return given;
86
+ return (0, ai_assistant_1.readTargetKeys)().find(key => (0, ai_assistant_1.queryToolName)(key) === given) ?? (0, ai_assistant_1.detailReadKeys)().find(key => (0, ai_assistant_1.detailToolName)(key) === given) ?? given;
87
+ }
88
+ /** A part of a definition without the fields the model left empty - `groupBy: null` is no grouping, not a column named null. */
89
+ function withoutEmpty(given) {
90
+ if (!given || typeof given !== 'object' || Array.isArray(given))
91
+ return given;
92
+ const kept = Object.entries(given).filter(([, value]) => value !== null && value !== undefined && value !== '');
93
+ return kept.length ? Object.fromEntries(kept) : undefined;
94
+ }
76
95
  /** The card in the person's domain - loaded late so the rules are tested without a database. */
77
96
  const cardInDomain = (context) => async (id) => {
78
97
  const [{ getRepository }, { DashboardCard }] = await Promise.all([Promise.resolve().then(() => __importStar(require('@things-factory/shell'))), Promise.resolve().then(() => __importStar(require('./dashboard-card.js')))]);
@@ -83,11 +102,21 @@ async function proposeDashboardCard(args, context, deps = {}) {
83
102
  const name = typeof args?.name === 'string' ? args.name.trim().slice(0, 100) : '';
84
103
  if (!name)
85
104
  return { rejected: true, error: 'no-name', message: 'give the card a short name in the person\'s language.' };
105
+ const where = withoutEmpty(args?.source?.where);
106
+ const rows = withoutEmpty(args?.rows);
107
+ /* One value, or the list `in` and `not_in` take - kept as the match's value either way. */
108
+ if (Array.isArray(rows?.match))
109
+ rows.match = rows.match.map((one) => {
110
+ if (!one || typeof one !== 'object' || !('values' in one))
111
+ return one;
112
+ const { values, ...match } = one;
113
+ return card_definition_js_1.LIST_OPS.includes(match.op) ? { ...match, value: values } : match.value === undefined ? { ...match, value: values } : match;
114
+ });
86
115
  const definition = {
87
116
  schemaVersion: card_definition_js_1.CARD_SCHEMA_VERSION,
88
- source: { read: args?.source?.read, ...(args?.source?.list ? { list: args.source.list } : {}), ...(args?.source?.where ? { where: args.source.where } : {}) },
89
- ...(args?.rows && Object.keys(args.rows).length ? { rows: args.rows } : {}),
90
- view: args?.view
117
+ source: { read: readKeyOf(args?.source?.read), ...(args?.source?.list ? { list: args.source.list } : {}), ...(where ? { where } : {}) },
118
+ ...(rows ? { rows } : {}),
119
+ view: withoutEmpty(args?.view)
91
120
  };
92
121
  const { source, issue } = (0, card_definition_js_1.sourceOf)(definition.source, ai_assistant_1.readTargetOf, ai_assistant_1.detailReadOf);
93
122
  if (!source) {
@@ -96,7 +125,7 @@ async function proposeDashboardCard(args, context, deps = {}) {
96
125
  error: issue.code,
97
126
  ...issue.params,
98
127
  ...(issue.code === 'unknown-read' || issue.code === 'not-a-card-source' ? { sources: cardSources() } : {}),
99
- message: 'the card must read one of the sources listed (a detail read by `read` and `list`). Read the data with its tool first, then call again.'
128
+ message: 'source.read is one of the sources listed - its read key or its tool (a detail read also names its list). Call again now with one of them.'
100
129
  };
101
130
  }
102
131
  const issues = (0, card_definition_js_1.checkDefinition)(definition, source);
@@ -110,8 +139,28 @@ async function proposeDashboardCard(args, context, deps = {}) {
110
139
  'a column is filtered with rows.match; a period with no date condition is a rows.match on a date column, or left out when the source is a state as of today.'
111
140
  };
112
141
  }
142
+ /* What the card says it shows, and whose rows it shows - checked before it runs, so a wrong card is never drawn once. */
143
+ const description = typeof args?.description === 'string' ? args.description : undefined;
144
+ const user = context?.state?.user;
145
+ const mine = cardSources().filter(one => one.mine).map(one => (one.list ? `${one.read} (list ${one.list})` : one.read));
146
+ const intent = (0, card_definition_js_1.checkCardIntent)({ name, description, definition }, source, { id: user?.id, name: user?.name, email: user?.email }, mine);
147
+ if (intent.length) {
148
+ return {
149
+ rejected: true,
150
+ error: 'card-says-otherwise',
151
+ issues: intent,
152
+ source: sourceSheet(source, definition.rows?.groupBy),
153
+ message: 'the card would not show what it says - fix each issue and call again now, in this turn. ' +
154
+ 'period-without-condition: put the period in source.where with relative values (this-month-start..this-month-end; a YYYY-MM condition this-month; the last 6 months -5m-start..this-month-end) or as a rows.match on a date column - or, when the source is a state as of today, take the period out of the name. ' +
155
+ 'period-held-to-fixed-days: use relative values so the card stays current. period-unlike-condition: make the condition the period the name says. ' +
156
+ 'viewer-filter-on-own-read: drop the filter - the read is the viewer\'s own whoever looks. viewer-filter-use-own-read: read one of the listed own reads instead, with no filter on the person.'
157
+ };
158
+ }
113
159
  /* A change is of one's own card, from the version it was read at - a newer version is not overwritten unseen. */
114
- const cardId = typeof args?.cardId === 'string' && args.cardId ? args.cardId : undefined;
160
+ const given = typeof args?.cardId === 'string' ? args.cardId.trim() : '';
161
+ const cardId = given ? (0, card_proposal_js_1.cardIdOf)(given) : undefined;
162
+ if (given && !cardId)
163
+ return { rejected: true, error: 'card-id-unreadable', cardId: given, message: `cardId is the card's uuid or its key ${card_names_js_1.CARD_AXIS}:<uuid>, as readDashboardCard gave it - call again now with it.` };
115
164
  let baseVersion;
116
165
  if (cardId) {
117
166
  const saved = await (deps.cardOf ?? cardInDomain(context))(cardId);
@@ -189,8 +238,10 @@ const spec = {
189
238
  doors: ['Mutation.saveDashboardCardProposal'],
190
239
  description: 'Offer a dashboard card - a definition the person saves to 나의 대시보드, drawn afterwards from the data without you. ' +
191
240
  'source.read is a read you have (a list target, or a detail read with source.list naming one of its lists); source.where holds its conditions or arguments - ' +
192
- 'for a period use relative values (today, this-month-start, this-month-end, last-month-start, this-year-start, -30d; for an integer year or month: this-year, last-month) so the card stays current. ' +
193
- `rows: match [{column, op: ${card_definition_js_1.MATCH_OPS.join('|')}, value}], groupBy (a date groups by month), sortBy (a column, or count when grouped), desc, limit. ` +
241
+ 'for a period use relative values so the card stays current - a day: today, -30d, this-month-start, this-month-end, last-month-start, this-year-start, -5m-start (the first day five months ago); ' +
242
+ 'an integer year or month: this-year, last-month; a month as YYYY-MM: this-month, last-month, -5m. The last 6 months is -5m-start..this-month-end. A name that says a period has that condition. ' +
243
+ `rows: match [{column, op: ${card_definition_js_1.MATCH_OPS.join('|')}, value}] - every match holds (two eq of one column never do: use in [..]); not_in [..] for "not one of"; groupBy (a date groups by month), sortBy (a column, or count when grouped), desc, limit. ` +
244
+ 'A read marked mine is the viewer\'s own rows, whoever looks - prefer it for "my ..." cards and never filter by a person\'s name or id. ' +
194
245
  `view.kind: ${card_definition_js_1.VIEW_KINDS.join('|')}; label is the column along the bottom of a chart (the groupBy column by default); values are the number columns summed or drawn (none counts rows); columns lists a table's columns. ` +
195
246
  'To change a saved card, pass its cardId and the version you changed as baseVersion.',
196
247
  schema: {
@@ -201,7 +252,7 @@ const spec = {
201
252
  source: {
202
253
  type: 'object',
203
254
  properties: {
204
- read: { type: 'string', description: 'The read key - office.receivables, office.cash-transaction.' },
255
+ read: { type: 'string', description: 'The read - its key (office.receivables) or the tool that reads it (readOfficeReceivables).' },
205
256
  list: { type: 'string', description: 'A detail read\'s list key.' },
206
257
  where: { type: 'object', description: 'Conditions or arguments by name; dates may be relative.', additionalProperties: true }
207
258
  },
@@ -212,7 +263,16 @@ const spec = {
212
263
  properties: {
213
264
  match: {
214
265
  type: 'array',
215
- items: { type: 'object', properties: { column: COLUMN, op: { type: 'string', enum: [...card_definition_js_1.MATCH_OPS] }, value: { type: 'string', description: 'A number, a day, a word or a relative date.' } }, required: ['column', 'op', 'value'] }
266
+ items: {
267
+ type: 'object',
268
+ properties: {
269
+ column: COLUMN,
270
+ op: { type: 'string', enum: [...card_definition_js_1.MATCH_OPS] },
271
+ value: { type: 'string', description: 'A number, a day, a word or a relative date.' },
272
+ values: { type: 'array', items: { type: 'string' }, description: `The values of ${card_definition_js_1.LIST_OPS.join(' and ')}, in place of value.` }
273
+ },
274
+ required: ['column', 'op']
275
+ }
216
276
  },
217
277
  groupBy: COLUMN,
218
278
  sortBy: COLUMN,
@@ -244,9 +304,12 @@ const spec = {
244
304
  * the card; the model reads it here, then offers the changed definition with cardId and baseVersion).
245
305
  */
246
306
  async function readDashboardCard(args, context, cardOf) {
247
- const id = typeof args?.id === 'string' ? args.id.trim().replace(/^dashboard-card:/, '') : '';
248
- if (!id)
307
+ const given = typeof args?.id === 'string' ? args.id.trim() : '';
308
+ if (!given)
249
309
  return { rejected: true, error: 'no-id', message: 'give the card id the person picked.' };
310
+ const id = (0, card_proposal_js_1.cardIdOf)(given);
311
+ if (!id)
312
+ return { rejected: true, error: 'card-id-unreadable', id: given, message: `a card is named by its key ${card_names_js_1.CARD_AXIS}:<uuid> (after [keys] dashboardCards) or its uuid - call again now with it.` };
250
313
  const found = await (cardOf ?? usableInDomain(context))(id);
251
314
  if (!found?.card)
252
315
  return { rejected: true, error: 'unknown-card', message: 'there is no such card - say so.' };
@@ -308,6 +371,14 @@ exports.cardCategory = {
308
371
  specs: [spec, readSpec]
309
372
  };
310
373
  (0, ai_client_base_1.registerToolCategory)(exports.cardCategory);
311
- /* In reach of every conversation, in front on the dashboard page only (ADR-0061 decision 9). */
312
- (0, ai_assistant_1.registerConversationCategory)({ name: card_names_js_1.CARD_CATEGORY, frontPages: [card_names_js_1.DASHBOARD_PAGE] });
374
+ /* In reach of every conversation, in front on the dashboard page and for a picked card (ADR-0061 decision 9). */
375
+ (0, ai_assistant_1.registerConversationCategory)({
376
+ name: card_names_js_1.CARD_CATEGORY,
377
+ frontPages: [card_names_js_1.DASHBOARD_PAGE],
378
+ frontAxes: [card_names_js_1.CARD_AXIS],
379
+ /* FINISH_RULE on this page: the card is what was asked for. */
380
+ pageRule: `This turn is asked from 나의 대시보드, where what the person asks to see - a figure, a total, a count, a list, a chart - is a dashboard card. ` +
381
+ `Read what it needs and end the turn with ${card_names_js_1.CARD_TOOL}, in this turn; never answer with the figure in words, and never ask whether to make it. ` +
382
+ `Only a question about the dashboard itself (how to share, how to move a card) is answered in words.`
383
+ });
313
384
  //# sourceMappingURL=card-tool.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"card-tool.js","sourceRoot":"","sources":["../../../server/service/card/card-tool.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * proposeDashboardCard - the assistant writes a card's definition in a conversation; the person saves it by pressing\n * the card (ADR-0160 decision 9).\n *\n * The server checks the definition against the read it names and runs it once as the person, so a card that cannot\n * be drawn is sent back with what the read has - never offered. The proposal carries the definition only: the\n * preview on the card is run again by whoever looks at the conversation, as themselves (decision 6), and the model\n * is told no values - its answer is read by everyone the conversation lets in, whatever door they pass.\n */\nimport { registerToolCategory, type ToolCategory, type ToolSpec } from '@things-factory/ai-client-base'\nimport {\n detailReadKeys,\n detailReadOf,\n readTargetKeys,\n readTargetOf,\n registerConversationCategory,\n runAsCaller,\n toolAccessFor\n} from '@things-factory/ai-assistant'\n\nimport { CARD_SCHEMA_VERSION, checkDefinition, MATCH_OPS, sourceOf, todayIn, VIEW_KINDS, type CardDefinition, type CardSource } from './card-definition.js'\nimport { runCard, shapedColumnNames } from './card-run.js'\n\nimport { CARD_CATEGORY, CARD_TOOL, DASHBOARD_PAGE } from './card-names.js'\n\nexport { CARD_CATEGORY, CARD_TOOL, DASHBOARD_PAGE }\n\n/** What a read offers a card - for a refusal the model fixes the definition from. */\nfunction sourceSheet(source: CardSource, groupBy?: string) {\n return {\n read: source.key,\n ...(source.list ? { list: source.list.key } : {}),\n /* What the rows are - a state as of today or a ledger over time - decides whether a period is a filter at all. */\n description: source.description,\n conditions: source.conditions.map(one => ({ name: one.name, type: one.type, ...(one.required ? { required: true } : {}), ...(one.values ? { values: one.values } : {}), ...(one.description ? { description: one.description } : {}) })),\n columns: source.columns.map(one => ({ name: one.name, type: one.type, ...(one.currency ? { currency: one.currency } : {}) })),\n ...(groupBy ? { columnsAfterGroupBy: [...shapedColumnNames(source, { groupBy }).keys()] } : {})\n }\n}\n\n/** The reads a card may name - list read targets, and detail reads with declared lists (`key/list`). */\nexport function cardSources(): string[] {\n return [\n ...readTargetKeys(),\n ...detailReadKeys().flatMap(key => (detailReadOf(key)?.lists ?? []).map(list => `${key}/${list.key}`))\n ]\n}\n\n/** A saved card as a change needs it - whose it is and its version. */\nexport type CardOf = (id: string) => Promise<{ ownerId?: string; version: number } | undefined>\n\n/** The card in the person's domain - loaded late so the rules are tested without a database. */\nconst cardInDomain =\n (context: any): CardOf =>\n async id => {\n const [{ getRepository }, { DashboardCard }] = await Promise.all([import('@things-factory/shell'), import('./dashboard-card.js')])\n const card = await getRepository(DashboardCard).findOne({ where: { id, domain: { id: context?.state?.domain?.id } } as any })\n return card ? { ownerId: card.ownerId, version: card.version } : undefined\n }\n\nexport async function proposeDashboardCard(args: any, context: any, deps: { run?: any; passesDoor?: (door: string) => Promise<boolean>; today?: string; cardOf?: CardOf } = {}) {\n const name = typeof args?.name === 'string' ? args.name.trim().slice(0, 100) : ''\n if (!name) return { rejected: true, error: 'no-name', message: 'give the card a short name in the person\\'s language.' }\n const definition: CardDefinition = {\n schemaVersion: CARD_SCHEMA_VERSION,\n source: { read: args?.source?.read, ...(args?.source?.list ? { list: args.source.list } : {}), ...(args?.source?.where ? { where: args.source.where } : {}) },\n ...(args?.rows && Object.keys(args.rows).length ? { rows: args.rows } : {}),\n view: args?.view\n }\n const { source, issue } = sourceOf(definition.source, readTargetOf, detailReadOf)\n if (!source) {\n return {\n rejected: true,\n error: issue!.code,\n ...issue!.params,\n ...(issue!.code === 'unknown-read' || issue!.code === 'not-a-card-source' ? { sources: cardSources() } : {}),\n message: 'the card must read one of the sources listed (a detail read by `read` and `list`). Read the data with its tool first, then call again.'\n }\n }\n const issues = checkDefinition(definition, source)\n if (issues.length) {\n return {\n rejected: true,\n error: 'definition-unfit',\n issues,\n source: sourceSheet(source, definition.rows?.groupBy),\n message:\n 'fix every issue against the source below and call again now, in this turn - do not ask the person. source.where takes only the conditions listed (give every required one); ' +\n 'a column is filtered with rows.match; a period with no date condition is a rows.match on a date column, or left out when the source is a state as of today.'\n }\n }\n\n /* A change is of one's own card, from the version it was read at - a newer version is not overwritten unseen. */\n const cardId = typeof args?.cardId === 'string' && args.cardId ? args.cardId : undefined\n let baseVersion: number | undefined\n if (cardId) {\n const saved = await (deps.cardOf ?? cardInDomain(context))(cardId)\n if (!saved) return { rejected: true, error: 'unknown-card', message: 'there is no such card - leave cardId out to offer a new one.' }\n if (saved.ownerId !== context?.state?.user?.id) return { rejected: true, error: 'not-your-card', message: 'only its owner changes a card - offer a new card instead, without cardId.' }\n baseVersion = Number.isInteger(args?.baseVersion) ? args.baseVersion : saved.version\n if (baseVersion !== saved.version) return { rejected: true, error: 'stale-version', current: saved.version, message: `the card is at version ${saved.version} now - start from it and call again.` }\n }\n\n /* Run once as the person - what cannot be drawn is not offered. */\n const ran = await runCard(definition, {\n readTargetOf,\n detailReadOf,\n passesDoor: deps.passesDoor ?? (door => toolAccessFor(context)(door)),\n run: deps.run ?? runAsCaller(context),\n today: deps.today ?? todayIn(context?.state?.domain?.timezone)\n })\n if (ran.issue) {\n return { rejected: true, error: ran.issue.code, ...(ran.issue.params ? { params: ran.issue.params } : {}), source: sourceSheet(source, definition.rows?.groupBy), message: 'the card could not be drawn - fix the definition and call again in this turn; say plainly if it cannot be.' }\n }\n /*\n * A table or chart that draws nothing today is offered only when the person asked for something that may be empty - a\n * request that expects rows was most likely read wrong (2026-10-24: 「이번 달 미수금」 filtered a state of today by the\n * contract date and drew nothing).\n */\n if (ran.counts && ran.counts.shown === 0 && definition.view.kind !== 'number' && args?.allowEmpty !== true) {\n return {\n rejected: true,\n error: 'draws-nothing',\n read: ran.counts.read,\n source: sourceSheet(source, definition.rows?.groupBy),\n message:\n `no row meets these conditions today (${ran.counts.read} read). Read the source's description: a state as of today takes no period filter. ` +\n 'Fix the conditions and call again now; only if the person asked for something that may well be empty, call again with allowEmpty: true.'\n }\n }\n /*\n * Bars or a line whose names repeat cannot be read - two bars of one customer are two contracts the reader cannot tell\n * apart (2026-10-24: 「미수금 상위 5곳」 drew one customer twice). Asked when the card is offered; a saved card draws as\n * its data stands.\n */\n const x: unknown[] = Array.isArray((ran.block as any)?.x) ? (ran.block as any).x : []\n if (!definition.rows?.groupBy && new Set(x).size < x.length) {\n const label = definition.view.label!\n return {\n rejected: true,\n error: 'label-repeats',\n label,\n use: `rows.groupBy: '${label}' (and sortBy a summed value)`,\n source: sourceSheet(source, label),\n message: `the bars' names (${label}) repeat - one name stands for several rows. Group by it so each name is one bar, and call again now, in this turn.`\n }\n }\n\n return {\n proposed: true,\n kind: 'dashboard-card',\n icon: 'dashboard_customize',\n label: name,\n card: {\n name,\n ...(typeof args?.description === 'string' && args.description.trim() ? { description: args.description.trim().slice(0, 300) } : {}),\n definition,\n ...(cardId ? { cardId, baseVersion } : {})\n },\n message:\n 'the card is offered with its preview; the person saves it to their dashboard by pressing it. Say in one line what it shows. ' +\n 'Do not ask whether to save it, and do not repeat its numbers - the preview shows them to whoever looks.'\n }\n}\n\nconst COLUMN = { type: 'string' }\n\nconst spec = {\n kind: 'read',\n name: CARD_TOOL,\n /* Only someone who may save a card is offered one. The data's doors are asked when it runs, as the person. */\n doors: ['Mutation.saveDashboardCardProposal'],\n description:\n 'Offer a dashboard card - a definition the person saves to 나의 대시보드, drawn afterwards from the data without you. ' +\n 'source.read is a read you have (a list target, or a detail read with source.list naming one of its lists); source.where holds its conditions or arguments - ' +\n 'for a period use relative values (today, this-month-start, this-month-end, last-month-start, this-year-start, -30d; for an integer year or month: this-year, last-month) so the card stays current. ' +\n `rows: match [{column, op: ${MATCH_OPS.join('|')}, value}], groupBy (a date groups by month), sortBy (a column, or count when grouped), desc, limit. ` +\n `view.kind: ${VIEW_KINDS.join('|')}; label is the column along the bottom of a chart (the groupBy column by default); values are the number columns summed or drawn (none counts rows); columns lists a table's columns. ` +\n 'To change a saved card, pass its cardId and the version you changed as baseVersion.',\n schema: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'The card name, short, in the person\\'s language.' },\n description: { type: 'string', description: 'One line of what it shows.' },\n source: {\n type: 'object',\n properties: {\n read: { type: 'string', description: 'The read key - office.receivables, office.cash-transaction.' },\n list: { type: 'string', description: 'A detail read\\'s list key.' },\n where: { type: 'object', description: 'Conditions or arguments by name; dates may be relative.', additionalProperties: true }\n },\n required: ['read']\n },\n rows: {\n type: 'object',\n properties: {\n match: {\n type: 'array',\n items: { type: 'object', properties: { column: COLUMN, op: { type: 'string', enum: [...MATCH_OPS] }, value: { type: 'string', description: 'A number, a day, a word or a relative date.' } }, required: ['column', 'op', 'value'] }\n },\n groupBy: COLUMN,\n sortBy: COLUMN,\n desc: { type: 'boolean' },\n limit: { type: 'integer' }\n }\n },\n view: {\n type: 'object',\n properties: {\n kind: { type: 'string', enum: [...VIEW_KINDS] },\n label: COLUMN,\n values: { type: 'array', items: COLUMN },\n columns: { type: 'array', items: COLUMN },\n unit: { type: 'string' }\n },\n required: ['kind']\n },\n allowEmpty: { type: 'boolean', description: 'true only when the person asked for something that may be empty today (overdue items, alerts).' },\n cardId: { type: 'string', description: 'A saved card being changed.' },\n baseVersion: { type: 'integer', description: 'The version of that card the change starts from.' }\n },\n required: ['name', 'source', 'view']\n },\n builder: (args: any, context: any) => proposeDashboardCard(args, context)\n} as ToolSpec\n\n/**\n * A saved card's name, version and definition - no values - for a change asked from the dashboard (「AI로 고치기」 picks\n * the card; the model reads it here, then offers the changed definition with cardId and baseVersion).\n */\nexport async function readDashboardCard(args: any, context: any, cardOf?: (id: string) => Promise<{ card?: any; access?: string }>) {\n const id = typeof args?.id === 'string' ? args.id.trim().replace(/^dashboard-card:/, '') : ''\n if (!id) return { rejected: true, error: 'no-id', message: 'give the card id the person picked.' }\n const found = await (cardOf ?? usableInDomain(context))(id)\n if (!found?.card) return { rejected: true, error: 'unknown-card', message: 'there is no such card - say so.' }\n if (!found.access) return { rejected: true, error: 'card-not-shared', message: 'this card is not shared with the person - say so.' }\n const { card, access } = found\n return {\n id: card.id,\n name: card.name,\n version: card.version,\n access,\n definition: card.definition,\n message:\n access === 'owner'\n ? `to change it, call ${CARD_TOOL} with the whole changed definition, cardId \"${card.id}\" and baseVersion ${card.version}.`\n : `the person does not own it - offer a new card (no cardId) made from this definition.`\n }\n}\n\n/** A card in the person's domain and how they may use it - loaded late so the rules are tested without a database. */\nconst usableInDomain =\n (context: any) =>\n async (id: string): Promise<{ card?: any; access?: string }> => {\n const [{ getRepository }, { DashboardCard, DashboardCardShare }, { cardAccessOf, departmentsOfEmployees }] = await Promise.all([\n import('@things-factory/shell'),\n import('./dashboard-card.js'),\n import('./card-access.js')\n ])\n const domainId = context?.state?.domain?.id\n const card = await getRepository(DashboardCard).findOne({ where: { id, domain: { id: domainId } } as any })\n if (!card) return {}\n const shares = await getRepository(DashboardCardShare).find({ where: { card: { id: card.id } } as any })\n let records: any[] | undefined\n try {\n const answer = await runAsCaller(context)('query { myEmployees { active department { id } } }', {})\n records = answer.errors?.length ? [] : answer.data?.myEmployees\n } catch {\n records = []\n }\n const access = cardAccessOf(card, { userId: context?.state?.user?.id, domainId, departmentIds: departmentsOfEmployees(records) }, shares)\n return { card, access }\n }\n\nconst readSpec = {\n kind: 'read',\n name: 'readDashboardCard',\n doors: ['Query.dashboardCardRun'],\n description: 'Read a saved dashboard card the person picked - its name, version and definition, never its values - before changing it.',\n schema: { type: 'object', properties: { id: { type: 'string', description: 'The card id the person picked.' } }, required: ['id'] },\n builder: (args: any, context: any) => readDashboardCard(args, context)\n} as ToolSpec\n\nexport const cardCategory: ToolCategory = {\n name: CARD_CATEGORY,\n description: 'dashboard cards - definitions the person saves and the dashboard draws from the data',\n guidance: [\n `- When the person asks for a card, a tile, a chart or a table on their dashboard (대시보드 카드, 카드로 만들어 줘), read the data with its read tool to learn its columns, then call ${CARD_TOOL} in the same turn. Never ask whether to make or save it; the card is the answer.`,\n `- A card is drawn later from the data as whoever opens it - you are not there. Put periods as relative values in source.where, never today's dates; say \"this month\" as this-month-start / this-month-end.`,\n `- \"Top N\" is rows.sortBy the amount, desc: true, limit N. Counting customers, places or months (상위 5곳, 거래처별, 월별) is rows.groupBy that column with view.values - each name one bar. Amounts in two currencies are never added - group or match by the currency, or use a column already in won.`,\n `- When ${CARD_TOOL} refuses, fix the definition from what it returns and call again in the same turn; if the data cannot be drawn this way, say so in one line.`,\n `- When the person picked a dashboard card to change (its id after [keys] dashboardCards), call readDashboardCard, then ${CARD_TOOL} with the whole changed definition, cardId and baseVersion - in the same turn. When the change makes its name untrue (top 5 → top 10), give it a true name.`\n ].join('\\n'),\n specs: [spec, readSpec]\n}\n\nregisterToolCategory(cardCategory)\n/* In reach of every conversation, in front on the dashboard page only (ADR-0061 decision 9). */\nregisterConversationCategory({ name: CARD_CATEGORY, frontPages: [DASHBOARD_PAGE] })\n"]}
1
+ {"version":3,"file":"card-tool.js","sourceRoot":"","sources":["../../../server/service/card/card-tool.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * proposeDashboardCard - the assistant writes a card's definition in a conversation; the person saves it by pressing\n * the card (ADR-0160 decision 9).\n *\n * The server checks the definition against the read it names and runs it once as the person, so a card that cannot\n * be drawn is sent back with what the read has - never offered. The proposal carries the definition only: the\n * preview on the card is run again by whoever looks at the conversation, as themselves (decision 6), and the model\n * is told no values - its answer is read by everyone the conversation lets in, whatever door they pass.\n */\nimport { registerToolCategory, type ToolCategory, type ToolSpec } from '@things-factory/ai-client-base'\nimport {\n detailReadKeys,\n detailReadOf,\n detailToolName,\n queryToolName,\n readTargetKeys,\n readTargetOf,\n registerConversationCategory,\n runAsCaller,\n toolAccessFor\n} from '@things-factory/ai-assistant'\n\nimport { CARD_SCHEMA_VERSION, checkCardIntent, checkDefinition, LIST_OPS, MATCH_OPS, sourceOf, todayIn, VIEW_KINDS, type CardDefinition, type CardSource } from './card-definition.js'\nimport { runCard, shapedColumnNames } from './card-run.js'\n\nimport { CARD_AXIS, CARD_CATEGORY, CARD_TOOL, DASHBOARD_PAGE } from './card-names.js'\nimport { cardIdOf } from './card-proposal.js'\n\nexport { CARD_CATEGORY, CARD_TOOL, DASHBOARD_PAGE }\n\n/** What a read offers a card - for a refusal the model fixes the definition from. */\nfunction sourceSheet(source: CardSource, groupBy?: string) {\n return {\n read: source.key,\n ...(source.list ? { list: source.list.key } : {}),\n /* What the rows are - a state as of today or a ledger over time - decides whether a period is a filter at all. */\n description: source.description,\n ...(source.mine ? { mine: 'the rows are the viewer\\'s own, whoever looks - no filter on a person' } : {}),\n conditions: source.conditions.map(one => ({ name: one.name, type: one.type, ...(one.format ? { format: 'YYYY-MM' } : {}), ...(one.many ? { takes: 'one value or a list' } : {}), ...(one.required ? { required: true } : {}), ...(one.values ? { values: one.values } : {}), ...(one.description ? { description: one.description } : {}) })),\n columns: source.columns.map(one => ({ name: one.name, type: one.type, ...(one.currency ? { currency: one.currency } : {}) })),\n ...(groupBy ? { columnsAfterGroupBy: [...shapedColumnNames(source, { groupBy }).keys()] } : {})\n }\n}\n\n/** The reads a card may name - each list read target and each detail read's list, with the tool the model knows it by. */\nexport function cardSources(): { read: string; list?: string; tool: string; mine?: true }[] {\n return [\n ...readTargetKeys().map(key => ({ read: key, tool: queryToolName(key), ...(readTargetOf(key)?.mine ? { mine: true as const } : {}) })),\n ...detailReadKeys().flatMap(key => (detailReadOf(key)?.lists ?? []).map(list => ({ read: key, list: list.key, tool: detailToolName(key), ...(detailReadOf(key)?.mine ? { mine: true as const } : {}) })))\n ]\n}\n\n/**\n * The read a model named - its key, or the name of the tool it reads it with (`queryPlantJobOrder` is `plant.job-order`):\n * the model knows reads by their tools, and named the tool as the card's source (2026-10-25, plant).\n */\nexport function readKeyOf(given: unknown): unknown {\n if (typeof given !== 'string' || readTargetOf(given) || detailReadOf(given)) return given\n return readTargetKeys().find(key => queryToolName(key) === given) ?? detailReadKeys().find(key => detailToolName(key) === given) ?? given\n}\n\n/** A part of a definition without the fields the model left empty - `groupBy: null` is no grouping, not a column named null. */\nfunction withoutEmpty<T extends Record<string, any>>(given: T | undefined): T | undefined {\n if (!given || typeof given !== 'object' || Array.isArray(given)) return given\n const kept = Object.entries(given).filter(([, value]) => value !== null && value !== undefined && value !== '')\n return kept.length ? (Object.fromEntries(kept) as T) : undefined\n}\n\n/** A saved card as a change needs it - whose it is and its version. */\nexport type CardOf = (id: string) => Promise<{ ownerId?: string; version: number } | undefined>\n\n/** The card in the person's domain - loaded late so the rules are tested without a database. */\nconst cardInDomain =\n (context: any): CardOf =>\n async id => {\n const [{ getRepository }, { DashboardCard }] = await Promise.all([import('@things-factory/shell'), import('./dashboard-card.js')])\n const card = await getRepository(DashboardCard).findOne({ where: { id, domain: { id: context?.state?.domain?.id } } as any })\n return card ? { ownerId: card.ownerId, version: card.version } : undefined\n }\n\nexport async function proposeDashboardCard(args: any, context: any, deps: { run?: any; passesDoor?: (door: string) => Promise<boolean>; today?: string; cardOf?: CardOf } = {}) {\n const name = typeof args?.name === 'string' ? args.name.trim().slice(0, 100) : ''\n if (!name) return { rejected: true, error: 'no-name', message: 'give the card a short name in the person\\'s language.' }\n const where = withoutEmpty(args?.source?.where)\n const rows = withoutEmpty(args?.rows)\n /* One value, or the list `in` and `not_in` take - kept as the match's value either way. */\n if (Array.isArray(rows?.match))\n rows.match = rows.match.map((one: any) => {\n if (!one || typeof one !== 'object' || !('values' in one)) return one\n const { values, ...match } = one\n return (LIST_OPS as readonly string[]).includes(match.op) ? { ...match, value: values } : match.value === undefined ? { ...match, value: values } : match\n })\n const definition: CardDefinition = {\n schemaVersion: CARD_SCHEMA_VERSION,\n source: { read: readKeyOf(args?.source?.read) as string, ...(args?.source?.list ? { list: args.source.list } : {}), ...(where ? { where } : {}) },\n ...(rows ? { rows } : {}),\n view: withoutEmpty(args?.view) as any\n }\n const { source, issue } = sourceOf(definition.source, readTargetOf, detailReadOf)\n if (!source) {\n return {\n rejected: true,\n error: issue!.code,\n ...issue!.params,\n ...(issue!.code === 'unknown-read' || issue!.code === 'not-a-card-source' ? { sources: cardSources() } : {}),\n message: 'source.read is one of the sources listed - its read key or its tool (a detail read also names its list). Call again now with one of them.'\n }\n }\n const issues = checkDefinition(definition, source)\n if (issues.length) {\n return {\n rejected: true,\n error: 'definition-unfit',\n issues,\n source: sourceSheet(source, definition.rows?.groupBy),\n message:\n 'fix every issue against the source below and call again now, in this turn - do not ask the person. source.where takes only the conditions listed (give every required one); ' +\n 'a column is filtered with rows.match; a period with no date condition is a rows.match on a date column, or left out when the source is a state as of today.'\n }\n }\n /* What the card says it shows, and whose rows it shows - checked before it runs, so a wrong card is never drawn once. */\n const description = typeof args?.description === 'string' ? args.description : undefined\n const user = context?.state?.user\n const mine = cardSources().filter(one => one.mine).map(one => (one.list ? `${one.read} (list ${one.list})` : one.read))\n const intent = checkCardIntent({ name, description, definition }, source, { id: user?.id, name: user?.name, email: user?.email }, mine)\n if (intent.length) {\n return {\n rejected: true,\n error: 'card-says-otherwise',\n issues: intent,\n source: sourceSheet(source, definition.rows?.groupBy),\n message:\n 'the card would not show what it says - fix each issue and call again now, in this turn. ' +\n 'period-without-condition: put the period in source.where with relative values (this-month-start..this-month-end; a YYYY-MM condition this-month; the last 6 months -5m-start..this-month-end) or as a rows.match on a date column - or, when the source is a state as of today, take the period out of the name. ' +\n 'period-held-to-fixed-days: use relative values so the card stays current. period-unlike-condition: make the condition the period the name says. ' +\n 'viewer-filter-on-own-read: drop the filter - the read is the viewer\\'s own whoever looks. viewer-filter-use-own-read: read one of the listed own reads instead, with no filter on the person.'\n }\n }\n\n /* A change is of one's own card, from the version it was read at - a newer version is not overwritten unseen. */\n const given = typeof args?.cardId === 'string' ? args.cardId.trim() : ''\n const cardId = given ? cardIdOf(given) : undefined\n if (given && !cardId) return { rejected: true, error: 'card-id-unreadable', cardId: given, message: `cardId is the card's uuid or its key ${CARD_AXIS}:<uuid>, as readDashboardCard gave it - call again now with it.` }\n let baseVersion: number | undefined\n if (cardId) {\n const saved = await (deps.cardOf ?? cardInDomain(context))(cardId)\n if (!saved) return { rejected: true, error: 'unknown-card', message: 'there is no such card - leave cardId out to offer a new one.' }\n if (saved.ownerId !== context?.state?.user?.id) return { rejected: true, error: 'not-your-card', message: 'only its owner changes a card - offer a new card instead, without cardId.' }\n baseVersion = Number.isInteger(args?.baseVersion) ? args.baseVersion : saved.version\n if (baseVersion !== saved.version) return { rejected: true, error: 'stale-version', current: saved.version, message: `the card is at version ${saved.version} now - start from it and call again.` }\n }\n\n /* Run once as the person - what cannot be drawn is not offered. */\n const ran = await runCard(definition, {\n readTargetOf,\n detailReadOf,\n passesDoor: deps.passesDoor ?? (door => toolAccessFor(context)(door)),\n run: deps.run ?? runAsCaller(context),\n today: deps.today ?? todayIn(context?.state?.domain?.timezone)\n })\n if (ran.issue) {\n return { rejected: true, error: ran.issue.code, ...(ran.issue.params ? { params: ran.issue.params } : {}), source: sourceSheet(source, definition.rows?.groupBy), message: 'the card could not be drawn - fix the definition and call again in this turn; say plainly if it cannot be.' }\n }\n /*\n * A table or chart that draws nothing today is offered only when the person asked for something that may be empty - a\n * request that expects rows was most likely read wrong (2026-10-24: 「이번 달 미수금」 filtered a state of today by the\n * contract date and drew nothing).\n */\n if (ran.counts && ran.counts.shown === 0 && definition.view.kind !== 'number' && args?.allowEmpty !== true) {\n return {\n rejected: true,\n error: 'draws-nothing',\n read: ran.counts.read,\n source: sourceSheet(source, definition.rows?.groupBy),\n message:\n `no row meets these conditions today (${ran.counts.read} read). Read the source's description: a state as of today takes no period filter. ` +\n 'Fix the conditions and call again now; only if the person asked for something that may well be empty, call again with allowEmpty: true.'\n }\n }\n /*\n * Bars or a line whose names repeat cannot be read - two bars of one customer are two contracts the reader cannot tell\n * apart (2026-10-24: 「미수금 상위 5곳」 drew one customer twice). Asked when the card is offered; a saved card draws as\n * its data stands.\n */\n const x: unknown[] = Array.isArray((ran.block as any)?.x) ? (ran.block as any).x : []\n if (!definition.rows?.groupBy && new Set(x).size < x.length) {\n const label = definition.view.label!\n return {\n rejected: true,\n error: 'label-repeats',\n label,\n use: `rows.groupBy: '${label}' (and sortBy a summed value)`,\n source: sourceSheet(source, label),\n message: `the bars' names (${label}) repeat - one name stands for several rows. Group by it so each name is one bar, and call again now, in this turn.`\n }\n }\n\n return {\n proposed: true,\n kind: 'dashboard-card',\n icon: 'dashboard_customize',\n label: name,\n card: {\n name,\n ...(typeof args?.description === 'string' && args.description.trim() ? { description: args.description.trim().slice(0, 300) } : {}),\n definition,\n ...(cardId ? { cardId, baseVersion } : {})\n },\n message:\n 'the card is offered with its preview; the person saves it to their dashboard by pressing it. Say in one line what it shows. ' +\n 'Do not ask whether to save it, and do not repeat its numbers - the preview shows them to whoever looks.'\n }\n}\n\nconst COLUMN = { type: 'string' }\n\nconst spec = {\n kind: 'read',\n name: CARD_TOOL,\n /* Only someone who may save a card is offered one. The data's doors are asked when it runs, as the person. */\n doors: ['Mutation.saveDashboardCardProposal'],\n description:\n 'Offer a dashboard card - a definition the person saves to 나의 대시보드, drawn afterwards from the data without you. ' +\n 'source.read is a read you have (a list target, or a detail read with source.list naming one of its lists); source.where holds its conditions or arguments - ' +\n 'for a period use relative values so the card stays current - a day: today, -30d, this-month-start, this-month-end, last-month-start, this-year-start, -5m-start (the first day five months ago); ' +\n 'an integer year or month: this-year, last-month; a month as YYYY-MM: this-month, last-month, -5m. The last 6 months is -5m-start..this-month-end. A name that says a period has that condition. ' +\n `rows: match [{column, op: ${MATCH_OPS.join('|')}, value}] - every match holds (two eq of one column never do: use in [..]); not_in [..] for \"not one of\"; groupBy (a date groups by month), sortBy (a column, or count when grouped), desc, limit. ` +\n 'A read marked mine is the viewer\\'s own rows, whoever looks - prefer it for \"my ...\" cards and never filter by a person\\'s name or id. ' +\n `view.kind: ${VIEW_KINDS.join('|')}; label is the column along the bottom of a chart (the groupBy column by default); values are the number columns summed or drawn (none counts rows); columns lists a table's columns. ` +\n 'To change a saved card, pass its cardId and the version you changed as baseVersion.',\n schema: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'The card name, short, in the person\\'s language.' },\n description: { type: 'string', description: 'One line of what it shows.' },\n source: {\n type: 'object',\n properties: {\n read: { type: 'string', description: 'The read - its key (office.receivables) or the tool that reads it (readOfficeReceivables).' },\n list: { type: 'string', description: 'A detail read\\'s list key.' },\n where: { type: 'object', description: 'Conditions or arguments by name; dates may be relative.', additionalProperties: true }\n },\n required: ['read']\n },\n rows: {\n type: 'object',\n properties: {\n match: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n column: COLUMN,\n op: { type: 'string', enum: [...MATCH_OPS] },\n value: { type: 'string', description: 'A number, a day, a word or a relative date.' },\n values: { type: 'array', items: { type: 'string' }, description: `The values of ${LIST_OPS.join(' and ')}, in place of value.` }\n },\n required: ['column', 'op']\n }\n },\n groupBy: COLUMN,\n sortBy: COLUMN,\n desc: { type: 'boolean' },\n limit: { type: 'integer' }\n }\n },\n view: {\n type: 'object',\n properties: {\n kind: { type: 'string', enum: [...VIEW_KINDS] },\n label: COLUMN,\n values: { type: 'array', items: COLUMN },\n columns: { type: 'array', items: COLUMN },\n unit: { type: 'string' }\n },\n required: ['kind']\n },\n allowEmpty: { type: 'boolean', description: 'true only when the person asked for something that may be empty today (overdue items, alerts).' },\n cardId: { type: 'string', description: 'A saved card being changed.' },\n baseVersion: { type: 'integer', description: 'The version of that card the change starts from.' }\n },\n required: ['name', 'source', 'view']\n },\n builder: (args: any, context: any) => proposeDashboardCard(args, context)\n} as ToolSpec\n\n/**\n * A saved card's name, version and definition - no values - for a change asked from the dashboard (「AI로 고치기」 picks\n * the card; the model reads it here, then offers the changed definition with cardId and baseVersion).\n */\nexport async function readDashboardCard(args: any, context: any, cardOf?: (id: string) => Promise<{ card?: any; access?: string }>) {\n const given = typeof args?.id === 'string' ? args.id.trim() : ''\n if (!given) return { rejected: true, error: 'no-id', message: 'give the card id the person picked.' }\n const id = cardIdOf(given)\n if (!id) return { rejected: true, error: 'card-id-unreadable', id: given, message: `a card is named by its key ${CARD_AXIS}:<uuid> (after [keys] dashboardCards) or its uuid - call again now with it.` }\n const found = await (cardOf ?? usableInDomain(context))(id)\n if (!found?.card) return { rejected: true, error: 'unknown-card', message: 'there is no such card - say so.' }\n if (!found.access) return { rejected: true, error: 'card-not-shared', message: 'this card is not shared with the person - say so.' }\n const { card, access } = found\n return {\n id: card.id,\n name: card.name,\n version: card.version,\n access,\n definition: card.definition,\n message:\n access === 'owner'\n ? `to change it, call ${CARD_TOOL} with the whole changed definition, cardId \"${card.id}\" and baseVersion ${card.version}.`\n : `the person does not own it - offer a new card (no cardId) made from this definition.`\n }\n}\n\n/** A card in the person's domain and how they may use it - loaded late so the rules are tested without a database. */\nconst usableInDomain =\n (context: any) =>\n async (id: string): Promise<{ card?: any; access?: string }> => {\n const [{ getRepository }, { DashboardCard, DashboardCardShare }, { cardAccessOf, departmentsOfEmployees }] = await Promise.all([\n import('@things-factory/shell'),\n import('./dashboard-card.js'),\n import('./card-access.js')\n ])\n const domainId = context?.state?.domain?.id\n const card = await getRepository(DashboardCard).findOne({ where: { id, domain: { id: domainId } } as any })\n if (!card) return {}\n const shares = await getRepository(DashboardCardShare).find({ where: { card: { id: card.id } } as any })\n let records: any[] | undefined\n try {\n const answer = await runAsCaller(context)('query { myEmployees { active department { id } } }', {})\n records = answer.errors?.length ? [] : answer.data?.myEmployees\n } catch {\n records = []\n }\n const access = cardAccessOf(card, { userId: context?.state?.user?.id, domainId, departmentIds: departmentsOfEmployees(records) }, shares)\n return { card, access }\n }\n\nconst readSpec = {\n kind: 'read',\n name: 'readDashboardCard',\n doors: ['Query.dashboardCardRun'],\n description: 'Read a saved dashboard card the person picked - its name, version and definition, never its values - before changing it.',\n schema: { type: 'object', properties: { id: { type: 'string', description: 'The card id the person picked.' } }, required: ['id'] },\n builder: (args: any, context: any) => readDashboardCard(args, context)\n} as ToolSpec\n\nexport const cardCategory: ToolCategory = {\n name: CARD_CATEGORY,\n description: 'dashboard cards - definitions the person saves and the dashboard draws from the data',\n guidance: [\n `- When the person asks for a card, a tile, a chart or a table on their dashboard (대시보드 카드, 카드로 만들어 줘), read the data with its read tool to learn its columns, then call ${CARD_TOOL} in the same turn. Never ask whether to make or save it; the card is the answer.`,\n `- A card is drawn later from the data as whoever opens it - you are not there. Put periods as relative values in source.where, never today's dates; say \"this month\" as this-month-start / this-month-end.`,\n `- \"Top N\" is rows.sortBy the amount, desc: true, limit N. Counting customers, places or months (상위 5곳, 거래처별, 월별) is rows.groupBy that column with view.values - each name one bar. Amounts in two currencies are never added - group or match by the currency, or use a column already in won.`,\n `- When ${CARD_TOOL} refuses, fix the definition from what it returns and call again in the same turn; if the data cannot be drawn this way, say so in one line.`,\n `- When the person picked a dashboard card to change (its id after [keys] dashboardCards), call readDashboardCard, then ${CARD_TOOL} with the whole changed definition, cardId and baseVersion - in the same turn. When the change makes its name untrue (top 5 → top 10), give it a true name.`\n ].join('\\n'),\n specs: [spec, readSpec]\n}\n\nregisterToolCategory(cardCategory)\n/* In reach of every conversation, in front on the dashboard page and for a picked card (ADR-0061 decision 9). */\nregisterConversationCategory({\n name: CARD_CATEGORY,\n frontPages: [DASHBOARD_PAGE],\n frontAxes: [CARD_AXIS],\n /* FINISH_RULE on this page: the card is what was asked for. */\n pageRule:\n `This turn is asked from 나의 대시보드, where what the person asks to see - a figure, a total, a count, a list, a chart - is a dashboard card. ` +\n `Read what it needs and end the turn with ${CARD_TOOL}, in this turn; never answer with the figure in words, and never ask whether to make it. ` +\n `Only a question about the dashboard itself (how to share, how to move a card) is answered in words.`\n})\n"]}
@@ -42,6 +42,7 @@ export declare class DashboardShareOptions {
42
42
  departmentsAvailable: boolean;
43
43
  departments: DashboardShareChoice[];
44
44
  peopleAvailable: boolean;
45
+ roles: DashboardShareChoice[];
45
46
  }
46
47
  export declare class DashboardCardShareInput {
47
48
  scope: DashboardCardShareScope;
@@ -9,11 +9,11 @@ let DashboardCardShareItem = class DashboardCardShareItem {
9
9
  };
10
10
  exports.DashboardCardShareItem = DashboardCardShareItem;
11
11
  tslib_1.__decorate([
12
- (0, type_graphql_1.Field)(type => dashboard_card_js_1.DashboardCardShareScope, { description: 'A person, a department or the domain.' }),
12
+ (0, type_graphql_1.Field)(type => dashboard_card_js_1.DashboardCardShareScope, { description: 'A person, a department, a role or the domain.' }),
13
13
  tslib_1.__metadata("design:type", String)
14
14
  ], DashboardCardShareItem.prototype, "scope", void 0);
15
15
  tslib_1.__decorate([
16
- (0, type_graphql_1.Field)({ description: 'The user, department or domain id.' }),
16
+ (0, type_graphql_1.Field)({ description: 'The user, department, role or domain id.' }),
17
17
  tslib_1.__metadata("design:type", String)
18
18
  ], DashboardCardShareItem.prototype, "targetId", void 0);
19
19
  tslib_1.__decorate([
@@ -166,6 +166,10 @@ tslib_1.__decorate([
166
166
  (0, type_graphql_1.Field)({ description: 'Whether the viewer may look people up to share with them.' }),
167
167
  tslib_1.__metadata("design:type", Boolean)
168
168
  ], DashboardShareOptions.prototype, "peopleAvailable", void 0);
169
+ tslib_1.__decorate([
170
+ (0, type_graphql_1.Field)(type => [DashboardShareChoice], { description: "The domain's roles, the ones it inherits included - a card shared with one reaches whoever holds it." }),
171
+ tslib_1.__metadata("design:type", Array)
172
+ ], DashboardShareOptions.prototype, "roles", void 0);
169
173
  exports.DashboardShareOptions = DashboardShareOptions = tslib_1.__decorate([
170
174
  (0, type_graphql_1.ObjectType)({ description: 'What a card may be shared with by the viewer.' })
171
175
  ], DashboardShareOptions);
@@ -173,11 +177,11 @@ let DashboardCardShareInput = class DashboardCardShareInput {
173
177
  };
174
178
  exports.DashboardCardShareInput = DashboardCardShareInput;
175
179
  tslib_1.__decorate([
176
- (0, type_graphql_1.Field)(type => dashboard_card_js_1.DashboardCardShareScope, { description: 'A person, a department or the domain.' }),
180
+ (0, type_graphql_1.Field)(type => dashboard_card_js_1.DashboardCardShareScope, { description: 'A person, a department, a role or the domain.' }),
177
181
  tslib_1.__metadata("design:type", String)
178
182
  ], DashboardCardShareInput.prototype, "scope", void 0);
179
183
  tslib_1.__decorate([
180
- (0, type_graphql_1.Field)({ description: 'The user, department or domain id.' }),
184
+ (0, type_graphql_1.Field)({ description: 'The user, department, role or domain id.' }),
181
185
  tslib_1.__metadata("design:type", String)
182
186
  ], DashboardCardShareInput.prototype, "targetId", void 0);
183
187
  tslib_1.__decorate([