@mulmoclaude/collection-plugin 0.3.0 → 0.4.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.
- package/dist/core/errorMessage.d.ts +5 -0
- package/dist/core/errorMessage.d.ts.map +1 -0
- package/dist/core/promptSafety.d.ts +2 -0
- package/dist/core/promptSafety.d.ts.map +1 -0
- package/dist/core/shortHexId.d.ts +9 -0
- package/dist/core/shortHexId.d.ts.map +1 -0
- package/dist/core/uiTypes.d.ts +26 -1
- package/dist/core/uiTypes.d.ts.map +1 -1
- package/dist/index.cjs +45 -126
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -86
- package/dist/index.js.map +1 -1
- package/dist/{calendarGrid-DZeLwBj9.cjs → promptSafety-BSO2gdsg.cjs} +184 -1
- package/dist/promptSafety-BSO2gdsg.cjs.map +1 -0
- package/dist/{calendarGrid-ggmFTZju.js → promptSafety-DShN_VCG.js} +113 -2
- package/dist/promptSafety-DShN_VCG.js.map +1 -0
- package/dist/style.css +544 -1
- package/dist/vue/collectionViewMode.d.ts +12 -0
- package/dist/vue/collectionViewMode.d.ts.map +1 -0
- package/dist/vue/components/CollectionCustomView.vue.d.ts +9 -0
- package/dist/vue/components/CollectionCustomView.vue.d.ts.map +1 -0
- package/dist/vue/components/CollectionView.vue.d.ts +41 -0
- package/dist/vue/components/CollectionView.vue.d.ts.map +1 -0
- package/dist/vue/components/CollectionViewConfigModal.vue.d.ts +16 -0
- package/dist/vue/components/CollectionViewConfigModal.vue.d.ts.map +1 -0
- package/dist/vue/components/CollectionsIndexView.vue.d.ts +4 -0
- package/dist/vue/components/CollectionsIndexView.vue.d.ts.map +1 -0
- package/dist/vue/components/FeedsView.vue.d.ts +4 -0
- package/dist/vue/components/FeedsView.vue.d.ts.map +1 -0
- package/dist/vue/index.d.ts +7 -1
- package/dist/vue/index.d.ts.map +1 -1
- package/dist/vue/lang/de.d.ts +4 -0
- package/dist/vue/lang/de.d.ts.map +1 -0
- package/dist/vue/lang/en.d.ts +98 -0
- package/dist/vue/lang/en.d.ts.map +1 -0
- package/dist/vue/lang/es.d.ts +4 -0
- package/dist/vue/lang/es.d.ts.map +1 -0
- package/dist/vue/lang/fr.d.ts +4 -0
- package/dist/vue/lang/fr.d.ts.map +1 -0
- package/dist/vue/lang/index.d.ts +111 -0
- package/dist/vue/lang/index.d.ts.map +1 -0
- package/dist/vue/lang/ja.d.ts +4 -0
- package/dist/vue/lang/ja.d.ts.map +1 -0
- package/dist/vue/lang/ko.d.ts +4 -0
- package/dist/vue/lang/ko.d.ts.map +1 -0
- package/dist/vue/lang/ptBR.d.ts +4 -0
- package/dist/vue/lang/ptBR.d.ts.map +1 -0
- package/dist/vue/lang/zh.d.ts +4 -0
- package/dist/vue/lang/zh.d.ts.map +1 -0
- package/dist/vue/uiContext.d.ts +143 -4
- package/dist/vue/uiContext.d.ts.map +1 -1
- package/dist/vue/useCollectionRendering.d.ts.map +1 -1
- package/dist/vue.cjs +3327 -238
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +3297 -217
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
- package/dist/calendarGrid-DZeLwBj9.cjs.map +0 -1
- package/dist/calendarGrid-ggmFTZju.js.map +0 -1
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Normalise an unknown thrown value to a display string. The view layer's host
|
|
2
|
+
* capabilities already return normalised `{ ok: false, error }` results, so this
|
|
3
|
+
* only backs the defensive `catch` around an unexpected throw. */
|
|
4
|
+
export declare function errorMessage(err: unknown): string;
|
|
5
|
+
//# sourceMappingURL=errorMessage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errorMessage.d.ts","sourceRoot":"","sources":["../../src/core/errorMessage.ts"],"names":[],"mappings":"AAAA;;mEAEmE;AACnE,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAEjD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promptSafety.d.ts","sourceRoot":"","sources":["../../src/core/promptSafety.ts"],"names":[],"mappings":"AAUA,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAErD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 8-char hex id — short, slug-safe, and editable. Produces the same id *shape*
|
|
3
|
+
* as the server's `generateItemId()` (8 hex chars) so a UI-created collection
|
|
4
|
+
* record looks like one the server would have generated for a form submitted
|
|
5
|
+
* with a blank primary key. The source of randomness differs (UUID-derived here
|
|
6
|
+
* vs `randomBytes` on the server); only the shape is intentionally shared.
|
|
7
|
+
*/
|
|
8
|
+
export declare function shortHexId(): string;
|
|
9
|
+
//# sourceMappingURL=shortHexId.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shortHexId.d.ts","sourceRoot":"","sources":["../../src/core/shortHexId.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC"}
|
package/dist/core/uiTypes.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CollectionDetail, CollectionItem, CollectionSchema } from "./schema";
|
|
1
|
+
import type { CollectionDetail, CollectionItem, CollectionSchema, CollectionSummary } from "./schema";
|
|
2
2
|
/** A record file the server couldn't load or that violates the schema —
|
|
3
3
|
* silently skipped at read time (mirror of the server `RecordIssue`). */
|
|
4
4
|
export interface CollectionRecordIssue {
|
|
@@ -79,4 +79,29 @@ export interface EmbedView {
|
|
|
79
79
|
* passes them in; this is the structural type the view layer accepts. The host's
|
|
80
80
|
* own `NotifierSeverity` is the identical union, so its maps pass through. */
|
|
81
81
|
export type CollectionNotifySeverity = "info" | "nudge" | "urgent";
|
|
82
|
+
/** Response of the collections list endpoint (`API_ROUTES.collections.list`). */
|
|
83
|
+
export interface CollectionsListResponse {
|
|
84
|
+
collections: CollectionSummary[];
|
|
85
|
+
}
|
|
86
|
+
/** A row in the feeds index — a data-source collection from the workspace's
|
|
87
|
+
* `feeds/` registry. */
|
|
88
|
+
export interface FeedSummary {
|
|
89
|
+
slug: string;
|
|
90
|
+
title: string;
|
|
91
|
+
icon: string;
|
|
92
|
+
kind: string;
|
|
93
|
+
schedule: string;
|
|
94
|
+
lastFetchedAt: string | null;
|
|
95
|
+
}
|
|
96
|
+
/** Response of the feeds list endpoint (`API_ROUTES.feeds.list`). */
|
|
97
|
+
export interface FeedsListResponse {
|
|
98
|
+
feeds: FeedSummary[];
|
|
99
|
+
}
|
|
100
|
+
/** The `{slug,title,icon}` triple the index pages reconcile pinned shortcuts
|
|
101
|
+
* against (prune dead slugs, refresh stale labels). */
|
|
102
|
+
export interface CollectionShortcutInfo {
|
|
103
|
+
slug: string;
|
|
104
|
+
title: string;
|
|
105
|
+
icon: string;
|
|
106
|
+
}
|
|
82
107
|
//# sourceMappingURL=uiTypes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uiTypes.d.ts","sourceRoot":"","sources":["../../src/core/uiTypes.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"uiTypes.d.ts","sourceRoot":"","sources":["../../src/core/uiTypes.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAEtG;0EAC0E;AAC1E,MAAM,WAAW,qBAAqB;IACpC,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,gBAAgB,CAAC;IAC7B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,qBAAqB,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,cAAc,CAAC;CACtB;AAED,uDAAuD;AACvD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/C,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/C,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IACvC,6DAA6D;IAC7D,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,+EAA+E;AAC/E,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACnD,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAErD;kCACkC;AAClC,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AAC1D,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAE1D,mFAAmF;AACnF,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,gBAAgB,CAAC;IACzB,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AACD,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAEzD,2DAA2D;AAC3D,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAKD,MAAM,WAAW,QAAQ;IACvB,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,KAAK,EAAE,OAAO,CAAC;IACf,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB;;yCAEqC;IACrC,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,kEAAkE;IAClE,UAAU,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;+EAG+E;AAC/E,MAAM,MAAM,wBAAwB,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;AAInE,iFAAiF;AACjF,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,iBAAiB,EAAE,CAAC;CAClC;AAED;yBACyB;AACzB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED;wDACwD;AACxD,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_schema = require("./schema-LrmrgW12.cjs");
|
|
3
|
-
const
|
|
3
|
+
const require_promptSafety = require("./promptSafety-BSO2gdsg.cjs");
|
|
4
4
|
const require_deriveAll = require("./deriveAll-BJ0Lvm1Q.cjs");
|
|
5
5
|
//#region src/core/presentCollection.ts
|
|
6
6
|
var TOOL_NAME = "presentCollection";
|
|
@@ -43,138 +43,57 @@ var executePresentCollection = async (_context, args) => {
|
|
|
43
43
|
};
|
|
44
44
|
};
|
|
45
45
|
//#endregion
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
var NON_SORTABLE = new Set([
|
|
50
|
-
"markdown",
|
|
51
|
-
"table",
|
|
52
|
-
"image",
|
|
53
|
-
"file",
|
|
54
|
-
"embed"
|
|
55
|
-
]);
|
|
56
|
-
function isSortableField(field) {
|
|
57
|
-
return !NON_SORTABLE.has(field.type);
|
|
58
|
-
}
|
|
59
|
-
/** Cycle one column's state: none → asc → desc → none. */
|
|
60
|
-
function nextSortDirection(current) {
|
|
61
|
-
if (current === null) return "asc";
|
|
62
|
-
if (current === "asc") return "desc";
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
function numericSortValue(raw) {
|
|
66
|
-
if (raw == null || raw === "") return EMPTY;
|
|
67
|
-
const num = typeof raw === "number" ? raw : Number(raw);
|
|
68
|
-
return Number.isFinite(num) ? {
|
|
69
|
-
empty: false,
|
|
70
|
-
num
|
|
71
|
-
} : EMPTY;
|
|
72
|
-
}
|
|
73
|
-
function stringSortValue(raw) {
|
|
74
|
-
if (raw == null) return EMPTY;
|
|
75
|
-
const str = String(raw);
|
|
76
|
-
return str.trim() === "" ? EMPTY : {
|
|
77
|
-
empty: false,
|
|
78
|
-
str
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
function dateSortValue(raw) {
|
|
82
|
-
if (raw == null || raw === "") return EMPTY;
|
|
83
|
-
const epoch = Date.parse(String(raw));
|
|
84
|
-
return Number.isNaN(epoch) ? stringSortValue(raw) : {
|
|
85
|
-
empty: false,
|
|
86
|
-
num: epoch
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
/** Enum sorts by the value's index in the declared `values` list. A value
|
|
90
|
-
* outside the list (or unset) is treated as empty → last. */
|
|
91
|
-
function enumSortValue(values, raw) {
|
|
92
|
-
if (raw == null || raw === "") return EMPTY;
|
|
93
|
-
const idx = values ? values.indexOf(String(raw)) : -1;
|
|
94
|
-
return idx < 0 ? EMPTY : {
|
|
95
|
-
empty: false,
|
|
96
|
-
num: idx
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
/** Boolean / toggle: false < true, never empty (unset reads as false). */
|
|
100
|
-
function boolSortValue(checked) {
|
|
101
|
-
return {
|
|
102
|
-
empty: false,
|
|
103
|
-
num: checked ? 1 : 0
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
function compareSortValues(left, right) {
|
|
107
|
-
if (left.num !== void 0 && right.num !== void 0) return left.num - right.num;
|
|
108
|
-
const leftStr = left.str ?? String(left.num ?? "");
|
|
109
|
-
const rightStr = right.str ?? String(right.num ?? "");
|
|
110
|
-
return leftStr.localeCompare(rightStr);
|
|
111
|
-
}
|
|
112
|
-
/** Stable sort of `items` by `valueOf`. Empties always last; ties hold
|
|
113
|
-
* source order. Returns a new array (does not mutate `items`). */
|
|
114
|
-
function sortItems(items, direction, valueOf) {
|
|
115
|
-
const dir = direction === "asc" ? 1 : -1;
|
|
116
|
-
return items.map((item, index) => ({
|
|
117
|
-
item,
|
|
118
|
-
index,
|
|
119
|
-
sv: valueOf(item)
|
|
120
|
-
})).sort((left, right) => {
|
|
121
|
-
if (left.sv.empty || right.sv.empty) {
|
|
122
|
-
if (left.sv.empty && right.sv.empty) return left.index - right.index;
|
|
123
|
-
return left.sv.empty ? 1 : -1;
|
|
124
|
-
}
|
|
125
|
-
const base = compareSortValues(left.sv, right.sv);
|
|
126
|
-
return base !== 0 ? base * dir : left.index - right.index;
|
|
127
|
-
}).map((decorated) => decorated.item);
|
|
128
|
-
}
|
|
129
|
-
//#endregion
|
|
130
|
-
exports.ENUM_ALERT = require_calendarGrid.ENUM_ALERT;
|
|
131
|
-
exports.ENUM_NEUTRAL = require_calendarGrid.ENUM_NEUTRAL;
|
|
132
|
-
exports.ENUM_NUDGE = require_calendarGrid.ENUM_NUDGE;
|
|
46
|
+
exports.ENUM_ALERT = require_promptSafety.ENUM_ALERT;
|
|
47
|
+
exports.ENUM_NEUTRAL = require_promptSafety.ENUM_NEUTRAL;
|
|
48
|
+
exports.ENUM_NUDGE = require_promptSafety.ENUM_NUDGE;
|
|
133
49
|
exports.FEED_SCHEDULES = require_schema.FEED_SCHEDULES;
|
|
134
50
|
exports.INGEST_KINDS = require_schema.INGEST_KINDS;
|
|
135
|
-
exports.MINUTES_PER_DAY =
|
|
51
|
+
exports.MINUTES_PER_DAY = require_promptSafety.MINUTES_PER_DAY;
|
|
136
52
|
exports.TOOL_DEFINITION = TOOL_DEFINITION;
|
|
137
53
|
exports.TOOL_NAME = TOOL_NAME;
|
|
138
|
-
exports.actionVisible =
|
|
139
|
-
exports.assignLanes =
|
|
140
|
-
exports.boolSortValue = boolSortValue;
|
|
141
|
-
exports.bucketRecords =
|
|
142
|
-
exports.buildMonthGrid =
|
|
143
|
-
exports.buildUpdatedRecord =
|
|
144
|
-
exports.coerceInlineValue =
|
|
145
|
-
exports.compareSortValues = compareSortValues;
|
|
146
|
-
exports.compareYmd =
|
|
147
|
-
exports.dateOf =
|
|
148
|
-
exports.dateSortValue = dateSortValue;
|
|
149
|
-
exports.daySlice =
|
|
54
|
+
exports.actionVisible = require_promptSafety.actionVisible;
|
|
55
|
+
exports.assignLanes = require_promptSafety.assignLanes;
|
|
56
|
+
exports.boolSortValue = require_promptSafety.boolSortValue;
|
|
57
|
+
exports.bucketRecords = require_promptSafety.bucketRecords;
|
|
58
|
+
exports.buildMonthGrid = require_promptSafety.buildMonthGrid;
|
|
59
|
+
exports.buildUpdatedRecord = require_promptSafety.buildUpdatedRecord;
|
|
60
|
+
exports.coerceInlineValue = require_promptSafety.coerceInlineValue;
|
|
61
|
+
exports.compareSortValues = require_promptSafety.compareSortValues;
|
|
62
|
+
exports.compareYmd = require_promptSafety.compareYmd;
|
|
63
|
+
exports.dateOf = require_promptSafety.dateOf;
|
|
64
|
+
exports.dateSortValue = require_promptSafety.dateSortValue;
|
|
65
|
+
exports.daySlice = require_promptSafety.daySlice;
|
|
66
|
+
exports.defangForPrompt = require_promptSafety.defangForPrompt;
|
|
150
67
|
exports.deriveAll = require_deriveAll.deriveAll;
|
|
151
|
-
exports.draftToRecord =
|
|
152
|
-
exports.emptyRow =
|
|
153
|
-
exports.enumColorClasses =
|
|
154
|
-
exports.enumSortValue = enumSortValue;
|
|
155
|
-
exports.enumValueIndex =
|
|
68
|
+
exports.draftToRecord = require_promptSafety.draftToRecord;
|
|
69
|
+
exports.emptyRow = require_promptSafety.emptyRow;
|
|
70
|
+
exports.enumColorClasses = require_promptSafety.enumColorClasses;
|
|
71
|
+
exports.enumSortValue = require_promptSafety.enumSortValue;
|
|
72
|
+
exports.enumValueIndex = require_promptSafety.enumValueIndex;
|
|
73
|
+
exports.errorMessage = require_promptSafety.errorMessage;
|
|
156
74
|
exports.evaluateDerived = require_deriveAll.evaluateDerived;
|
|
157
75
|
exports.executePresentCollection = executePresentCollection;
|
|
158
|
-
exports.fieldVisible =
|
|
159
|
-
exports.firstMissingRequiredField =
|
|
160
|
-
exports.isSortableField = isSortableField;
|
|
161
|
-
exports.itemIdOf =
|
|
162
|
-
exports.itemLabelOf =
|
|
163
|
-
exports.labelFieldFor =
|
|
164
|
-
exports.monthAnchorDate =
|
|
165
|
-
exports.nextSortDirection = nextSortDirection;
|
|
166
|
-
exports.numericSortValue = numericSortValue;
|
|
167
|
-
exports.parseIsoDate =
|
|
168
|
-
exports.parseIsoDateTime =
|
|
169
|
-
exports.parseTimeRange =
|
|
170
|
-
exports.recordSpan =
|
|
171
|
-
exports.resolveEnumColor =
|
|
76
|
+
exports.fieldVisible = require_promptSafety.fieldVisible;
|
|
77
|
+
exports.firstMissingRequiredField = require_promptSafety.firstMissingRequiredField;
|
|
78
|
+
exports.isSortableField = require_promptSafety.isSortableField;
|
|
79
|
+
exports.itemIdOf = require_promptSafety.itemIdOf;
|
|
80
|
+
exports.itemLabelOf = require_promptSafety.itemLabelOf;
|
|
81
|
+
exports.labelFieldFor = require_promptSafety.labelFieldFor;
|
|
82
|
+
exports.monthAnchorDate = require_promptSafety.monthAnchorDate;
|
|
83
|
+
exports.nextSortDirection = require_promptSafety.nextSortDirection;
|
|
84
|
+
exports.numericSortValue = require_promptSafety.numericSortValue;
|
|
85
|
+
exports.parseIsoDate = require_promptSafety.parseIsoDate;
|
|
86
|
+
exports.parseIsoDateTime = require_promptSafety.parseIsoDateTime;
|
|
87
|
+
exports.parseTimeRange = require_promptSafety.parseTimeRange;
|
|
88
|
+
exports.recordSpan = require_promptSafety.recordSpan;
|
|
89
|
+
exports.resolveEnumColor = require_promptSafety.resolveEnumColor;
|
|
172
90
|
exports.resolveRowRefs = require_deriveAll.resolveRowRefs;
|
|
173
|
-
exports.rowFromItem =
|
|
174
|
-
exports.
|
|
175
|
-
exports.
|
|
176
|
-
exports.
|
|
177
|
-
exports.
|
|
178
|
-
exports.
|
|
91
|
+
exports.rowFromItem = require_promptSafety.rowFromItem;
|
|
92
|
+
exports.shortHexId = require_promptSafety.shortHexId;
|
|
93
|
+
exports.sortItems = require_promptSafety.sortItems;
|
|
94
|
+
exports.spanCoversDay = require_promptSafety.spanCoversDay;
|
|
95
|
+
exports.stringSortValue = require_promptSafety.stringSortValue;
|
|
96
|
+
exports.whenMatches = require_promptSafety.whenMatches;
|
|
97
|
+
exports.ymdKey = require_promptSafety.ymdKey;
|
|
179
98
|
|
|
180
99
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/core/presentCollection.ts","../src/core/sortItems.ts"],"sourcesContent":["// presentCollection tool — definition + pure server-side executor.\n//\n// Isomorphic (no Vue, no Node): bundled to the browser as the plugin's\n// `execute`, and run server-side via the host's plugin dispatch route. The\n// executor only validates + echoes the addressing; the live schema + items\n// are fetched client-side by the View through the host's /api/collections\n// routes, so a bad slug surfaces as the View's \"not found\" state.\n\nimport type { ToolContext, ToolDefinition, ToolResult } from \"gui-chat-protocol\";\n\nexport const TOOL_NAME = \"presentCollection\";\n\n/** Render payload carried in the tool result's `data` field; the View mounts\n * off these. Same shape as the tool args. */\nexport interface PresentCollectionData {\n /** Slug of the collection to display (e.g. \"clients\", \"invoices\"). */\n collectionSlug: string;\n /** Optional primary-key value of a single item to open on mount. */\n itemId?: string;\n}\n\nexport type PresentCollectionArgs = PresentCollectionData;\n\nexport const TOOL_DEFINITION: ToolDefinition = {\n type: \"function\",\n name: TOOL_NAME,\n description:\n \"Display a schema-driven collection inline in the chat as an interactive, editable card. Shows the collection's list of records. Pass `itemId` to open one specific record on mount.\",\n parameters: {\n type: \"object\",\n properties: {\n collectionSlug: {\n type: \"string\",\n description: \"The slug of the collection to display (e.g. 'clients', 'invoices', 'contacts').\",\n },\n itemId: {\n type: \"string\",\n description: \"Optional primary-key value of a single record to open in detail view on mount. Omit to show the full list.\",\n },\n },\n required: [\"collectionSlug\"],\n },\n prompt: `After making changes to schema-driven collections, use ${TOOL_NAME} to present either the collection or the item`,\n};\n\nexport const executePresentCollection = async (\n _context: ToolContext,\n args: PresentCollectionArgs,\n): Promise<ToolResult<PresentCollectionData, PresentCollectionData>> => {\n const collectionSlug = typeof args?.collectionSlug === \"string\" ? args.collectionSlug.trim() : \"\";\n if (!collectionSlug) {\n return {\n message: \"presentCollection error: collectionSlug is required\",\n instructions: \"Tell the user you couldn't display the collection because no collection was specified, and ask which collection they mean.\",\n };\n }\n const itemId = typeof args.itemId === \"string\" && args.itemId.trim().length > 0 ? args.itemId.trim() : undefined;\n const data: PresentCollectionData = itemId ? { collectionSlug, itemId } : { collectionSlug };\n const target = itemId ? `${collectionSlug} / ${itemId}` : collectionSlug;\n return {\n message: `Presented collection ${target}`,\n // `data` is the view's source (also the host's render-eligibility signal);\n // `jsonData` is what the LLM sees. Same payload, two audiences.\n data,\n jsonData: data,\n instructions:\n \"The collection has been presented to the user as an interactive card. They can browse, open, edit, create, and delete records directly. No further action is needed unless they ask.\",\n };\n};\n","// Sorting for the collection list table. The header sort toggle (next to\n// each field title) cycles a single active column through none → asc →\n// desc → none; this module turns that state plus a per-field value\n// extractor into an ordered copy of the rows.\n//\n// Two invariants the comparator guarantees:\n// 1. Rows with an empty/missing value for the sorted field always sink\n// to the bottom, regardless of direction.\n// 2. Ties (and the empty group) keep their original order — the sort is\n// stable via the captured source index.\n//\n// Field-type → comparable mapping (see `isSortableField`):\n// string/text/email → string · number/money → numeric ·\n// date/datetime → epoch-ms · enum → declared-index · boolean/toggle →\n// false<true · ref → display label · derived → its display type.\n// markdown/table/image/file/embed get no sort button.\n\nimport type { CollectionItem, CollectionFieldSpec, CollectionFieldType } from \"./schema\";\n\nexport type SortDirection = \"asc\" | \"desc\";\n\nexport interface SortState {\n /** Field key of the single active sort column. */\n field: string;\n direction: SortDirection;\n}\n\n/** A row's comparable value for the active field. Exactly one of `num` /\n * `str` is set when not empty; `empty` rows always sort last. */\nexport interface SortValue {\n empty: boolean;\n num?: number;\n str?: string;\n}\n\nconst EMPTY: SortValue = { empty: true };\n\n/** Field types that render no value text in the table, so offer no sort. */\nconst NON_SORTABLE: ReadonlySet<CollectionFieldType> = new Set<CollectionFieldType>([\"markdown\", \"table\", \"image\", \"file\", \"embed\"]);\n\nexport function isSortableField(field: CollectionFieldSpec): boolean {\n return !NON_SORTABLE.has(field.type);\n}\n\n/** Cycle one column's state: none → asc → desc → none. */\nexport function nextSortDirection(current: SortDirection | null): SortDirection | null {\n if (current === null) return \"asc\";\n if (current === \"asc\") return \"desc\";\n return null;\n}\n\n// ── SortValue constructors (one per comparable kind) ────────────────\n\nexport function numericSortValue(raw: unknown): SortValue {\n if (raw == null || raw === \"\") return EMPTY;\n const num = typeof raw === \"number\" ? raw : Number(raw);\n return Number.isFinite(num) ? { empty: false, num } : EMPTY;\n}\n\nexport function stringSortValue(raw: unknown): SortValue {\n if (raw == null) return EMPTY;\n const str = String(raw);\n return str.trim() === \"\" ? EMPTY : { empty: false, str };\n}\n\nexport function dateSortValue(raw: unknown): SortValue {\n if (raw == null || raw === \"\") return EMPTY;\n const epoch = Date.parse(String(raw));\n // Unparseable dates fall back to a lexical compare rather than vanishing.\n return Number.isNaN(epoch) ? stringSortValue(raw) : { empty: false, num: epoch };\n}\n\n/** Enum sorts by the value's index in the declared `values` list. A value\n * outside the list (or unset) is treated as empty → last. */\nexport function enumSortValue(values: readonly string[] | undefined, raw: unknown): SortValue {\n if (raw == null || raw === \"\") return EMPTY;\n const idx = values ? values.indexOf(String(raw)) : -1;\n return idx < 0 ? EMPTY : { empty: false, num: idx };\n}\n\n/** Boolean / toggle: false < true, never empty (unset reads as false). */\nexport function boolSortValue(checked: boolean): SortValue {\n return { empty: false, num: checked ? 1 : 0 };\n}\n\n// ── Comparator + driver ─────────────────────────────────────────────\n\nexport function compareSortValues(left: SortValue, right: SortValue): number {\n if (left.num !== undefined && right.num !== undefined) return left.num - right.num;\n const leftStr = left.str ?? String(left.num ?? \"\");\n const rightStr = right.str ?? String(right.num ?? \"\");\n return leftStr.localeCompare(rightStr);\n}\n\n/** Stable sort of `items` by `valueOf`. Empties always last; ties hold\n * source order. Returns a new array (does not mutate `items`). */\nexport function sortItems(items: readonly CollectionItem[], direction: SortDirection, valueOf: (item: CollectionItem) => SortValue): CollectionItem[] {\n const dir = direction === \"asc\" ? 1 : -1;\n return items\n .map((item, index) => ({ item, index, sv: valueOf(item) }))\n .sort((left, right) => {\n if (left.sv.empty || right.sv.empty) {\n if (left.sv.empty && right.sv.empty) return left.index - right.index;\n return left.sv.empty ? 1 : -1;\n }\n const base = compareSortValues(left.sv, right.sv);\n return base !== 0 ? base * dir : left.index - right.index;\n })\n .map((decorated) => decorated.item);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/core/presentCollection.ts"],"sourcesContent":["// presentCollection tool — definition + pure server-side executor.\n//\n// Isomorphic (no Vue, no Node): bundled to the browser as the plugin's\n// `execute`, and run server-side via the host's plugin dispatch route. The\n// executor only validates + echoes the addressing; the live schema + items\n// are fetched client-side by the View through the host's /api/collections\n// routes, so a bad slug surfaces as the View's \"not found\" state.\n\nimport type { ToolContext, ToolDefinition, ToolResult } from \"gui-chat-protocol\";\n\nexport const TOOL_NAME = \"presentCollection\";\n\n/** Render payload carried in the tool result's `data` field; the View mounts\n * off these. Same shape as the tool args. */\nexport interface PresentCollectionData {\n /** Slug of the collection to display (e.g. \"clients\", \"invoices\"). */\n collectionSlug: string;\n /** Optional primary-key value of a single item to open on mount. */\n itemId?: string;\n}\n\nexport type PresentCollectionArgs = PresentCollectionData;\n\nexport const TOOL_DEFINITION: ToolDefinition = {\n type: \"function\",\n name: TOOL_NAME,\n description:\n \"Display a schema-driven collection inline in the chat as an interactive, editable card. Shows the collection's list of records. Pass `itemId` to open one specific record on mount.\",\n parameters: {\n type: \"object\",\n properties: {\n collectionSlug: {\n type: \"string\",\n description: \"The slug of the collection to display (e.g. 'clients', 'invoices', 'contacts').\",\n },\n itemId: {\n type: \"string\",\n description: \"Optional primary-key value of a single record to open in detail view on mount. Omit to show the full list.\",\n },\n },\n required: [\"collectionSlug\"],\n },\n prompt: `After making changes to schema-driven collections, use ${TOOL_NAME} to present either the collection or the item`,\n};\n\nexport const executePresentCollection = async (\n _context: ToolContext,\n args: PresentCollectionArgs,\n): Promise<ToolResult<PresentCollectionData, PresentCollectionData>> => {\n const collectionSlug = typeof args?.collectionSlug === \"string\" ? args.collectionSlug.trim() : \"\";\n if (!collectionSlug) {\n return {\n message: \"presentCollection error: collectionSlug is required\",\n instructions: \"Tell the user you couldn't display the collection because no collection was specified, and ask which collection they mean.\",\n };\n }\n const itemId = typeof args.itemId === \"string\" && args.itemId.trim().length > 0 ? args.itemId.trim() : undefined;\n const data: PresentCollectionData = itemId ? { collectionSlug, itemId } : { collectionSlug };\n const target = itemId ? `${collectionSlug} / ${itemId}` : collectionSlug;\n return {\n message: `Presented collection ${target}`,\n // `data` is the view's source (also the host's render-eligibility signal);\n // `jsonData` is what the LLM sees. Same payload, two audiences.\n data,\n jsonData: data,\n instructions:\n \"The collection has been presented to the user as an interactive card. They can browse, open, edit, create, and delete records directly. No further action is needed unless they ask.\",\n };\n};\n"],"mappings":";;;;;AAUA,IAAa,YAAY;AAazB,IAAa,kBAAkC;CAC7C,MAAM;CACN,MAAM;CACN,aACE;CACF,YAAY;EACV,MAAM;EACN,YAAY;GACV,gBAAgB;IACd,MAAM;IACN,aAAa;GACf;GACA,QAAQ;IACN,MAAM;IACN,aAAa;GACf;EACF;EACA,UAAU,CAAC,gBAAgB;CAC7B;CACA,QAAQ,0DAA0D,UAAU;AAC9E;AAEA,IAAa,2BAA2B,OACtC,UACA,SACsE;CACtE,MAAM,iBAAiB,OAAO,MAAM,mBAAmB,WAAW,KAAK,eAAe,KAAK,IAAI;CAC/F,IAAI,CAAC,gBACH,OAAO;EACL,SAAS;EACT,cAAc;CAChB;CAEF,MAAM,SAAS,OAAO,KAAK,WAAW,YAAY,KAAK,OAAO,KAAK,EAAE,SAAS,IAAI,KAAK,OAAO,KAAK,IAAI,KAAA;CACvG,MAAM,OAA8B,SAAS;EAAE;EAAgB;CAAO,IAAI,EAAE,eAAe;CAE3F,OAAO;EACL,SAAS,wBAFI,SAAS,GAAG,eAAe,KAAK,WAAW;EAKxD;EACA,UAAU;EACV,cACE;CACJ;AACF"}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,4 +9,7 @@ export * from "./core/deriveAll";
|
|
|
9
9
|
export * from "./core/sortItems";
|
|
10
10
|
export * from "./core/itemLabel";
|
|
11
11
|
export * from "./core/calendarGrid";
|
|
12
|
+
export * from "./core/errorMessage";
|
|
13
|
+
export * from "./core/shortHexId";
|
|
14
|
+
export * from "./core/promptSafety";
|
|
12
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,0BAA0B,CAAC;AACzC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,0BAA0B,CAAC;AACzC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as INGEST_KINDS, t as FEED_SCHEDULES } from "./schema-DyfSfVzh.js";
|
|
2
|
-
import { A as
|
|
2
|
+
import { A as buildUpdatedRecord, B as ENUM_NEUTRAL, C as dateSortValue, D as numericSortValue, E as nextSortDirection, F as rowFromItem, H as enumColorClasses, I as actionVisible, L as fieldVisible, M as draftToRecord, N as emptyRow, O as sortItems, P as firstMissingRequiredField, R as whenMatches, S as compareSortValues, T as isSortableField, U as enumValueIndex, V as ENUM_NUDGE, W as resolveEnumColor, _ as ymdKey, a as assignLanes, b as labelFieldFor, c as compareYmd, d as monthAnchorDate, f as parseIsoDate, g as spanCoversDay, h as recordSpan, i as MINUTES_PER_DAY, j as coerceInlineValue, k as stringSortValue, l as dateOf, m as parseTimeRange, n as shortHexId, o as bucketRecords, p as parseIsoDateTime, r as errorMessage, s as buildMonthGrid, t as defangForPrompt, u as daySlice, v as itemIdOf, w as enumSortValue, x as boolSortValue, y as itemLabelOf, z as ENUM_ALERT } from "./promptSafety-DShN_VCG.js";
|
|
3
3
|
import { n as resolveRowRefs, r as evaluateDerived, t as deriveAll } from "./deriveAll-BHcs1erT.js";
|
|
4
4
|
//#region src/core/presentCollection.ts
|
|
5
5
|
var TOOL_NAME = "presentCollection";
|
|
@@ -42,90 +42,6 @@ var executePresentCollection = async (_context, args) => {
|
|
|
42
42
|
};
|
|
43
43
|
};
|
|
44
44
|
//#endregion
|
|
45
|
-
|
|
46
|
-
var EMPTY = { empty: true };
|
|
47
|
-
/** Field types that render no value text in the table, so offer no sort. */
|
|
48
|
-
var NON_SORTABLE = new Set([
|
|
49
|
-
"markdown",
|
|
50
|
-
"table",
|
|
51
|
-
"image",
|
|
52
|
-
"file",
|
|
53
|
-
"embed"
|
|
54
|
-
]);
|
|
55
|
-
function isSortableField(field) {
|
|
56
|
-
return !NON_SORTABLE.has(field.type);
|
|
57
|
-
}
|
|
58
|
-
/** Cycle one column's state: none → asc → desc → none. */
|
|
59
|
-
function nextSortDirection(current) {
|
|
60
|
-
if (current === null) return "asc";
|
|
61
|
-
if (current === "asc") return "desc";
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
function numericSortValue(raw) {
|
|
65
|
-
if (raw == null || raw === "") return EMPTY;
|
|
66
|
-
const num = typeof raw === "number" ? raw : Number(raw);
|
|
67
|
-
return Number.isFinite(num) ? {
|
|
68
|
-
empty: false,
|
|
69
|
-
num
|
|
70
|
-
} : EMPTY;
|
|
71
|
-
}
|
|
72
|
-
function stringSortValue(raw) {
|
|
73
|
-
if (raw == null) return EMPTY;
|
|
74
|
-
const str = String(raw);
|
|
75
|
-
return str.trim() === "" ? EMPTY : {
|
|
76
|
-
empty: false,
|
|
77
|
-
str
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
function dateSortValue(raw) {
|
|
81
|
-
if (raw == null || raw === "") return EMPTY;
|
|
82
|
-
const epoch = Date.parse(String(raw));
|
|
83
|
-
return Number.isNaN(epoch) ? stringSortValue(raw) : {
|
|
84
|
-
empty: false,
|
|
85
|
-
num: epoch
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
/** Enum sorts by the value's index in the declared `values` list. A value
|
|
89
|
-
* outside the list (or unset) is treated as empty → last. */
|
|
90
|
-
function enumSortValue(values, raw) {
|
|
91
|
-
if (raw == null || raw === "") return EMPTY;
|
|
92
|
-
const idx = values ? values.indexOf(String(raw)) : -1;
|
|
93
|
-
return idx < 0 ? EMPTY : {
|
|
94
|
-
empty: false,
|
|
95
|
-
num: idx
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
/** Boolean / toggle: false < true, never empty (unset reads as false). */
|
|
99
|
-
function boolSortValue(checked) {
|
|
100
|
-
return {
|
|
101
|
-
empty: false,
|
|
102
|
-
num: checked ? 1 : 0
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
function compareSortValues(left, right) {
|
|
106
|
-
if (left.num !== void 0 && right.num !== void 0) return left.num - right.num;
|
|
107
|
-
const leftStr = left.str ?? String(left.num ?? "");
|
|
108
|
-
const rightStr = right.str ?? String(right.num ?? "");
|
|
109
|
-
return leftStr.localeCompare(rightStr);
|
|
110
|
-
}
|
|
111
|
-
/** Stable sort of `items` by `valueOf`. Empties always last; ties hold
|
|
112
|
-
* source order. Returns a new array (does not mutate `items`). */
|
|
113
|
-
function sortItems(items, direction, valueOf) {
|
|
114
|
-
const dir = direction === "asc" ? 1 : -1;
|
|
115
|
-
return items.map((item, index) => ({
|
|
116
|
-
item,
|
|
117
|
-
index,
|
|
118
|
-
sv: valueOf(item)
|
|
119
|
-
})).sort((left, right) => {
|
|
120
|
-
if (left.sv.empty || right.sv.empty) {
|
|
121
|
-
if (left.sv.empty && right.sv.empty) return left.index - right.index;
|
|
122
|
-
return left.sv.empty ? 1 : -1;
|
|
123
|
-
}
|
|
124
|
-
const base = compareSortValues(left.sv, right.sv);
|
|
125
|
-
return base !== 0 ? base * dir : left.index - right.index;
|
|
126
|
-
}).map((decorated) => decorated.item);
|
|
127
|
-
}
|
|
128
|
-
//#endregion
|
|
129
|
-
export { ENUM_ALERT, ENUM_NEUTRAL, ENUM_NUDGE, FEED_SCHEDULES, INGEST_KINDS, MINUTES_PER_DAY, TOOL_DEFINITION, TOOL_NAME, actionVisible, assignLanes, boolSortValue, bucketRecords, buildMonthGrid, buildUpdatedRecord, coerceInlineValue, compareSortValues, compareYmd, dateOf, dateSortValue, daySlice, deriveAll, draftToRecord, emptyRow, enumColorClasses, enumSortValue, enumValueIndex, evaluateDerived, executePresentCollection, fieldVisible, firstMissingRequiredField, isSortableField, itemIdOf, itemLabelOf, labelFieldFor, monthAnchorDate, nextSortDirection, numericSortValue, parseIsoDate, parseIsoDateTime, parseTimeRange, recordSpan, resolveEnumColor, resolveRowRefs, rowFromItem, sortItems, spanCoversDay, stringSortValue, whenMatches, ymdKey };
|
|
45
|
+
export { ENUM_ALERT, ENUM_NEUTRAL, ENUM_NUDGE, FEED_SCHEDULES, INGEST_KINDS, MINUTES_PER_DAY, TOOL_DEFINITION, TOOL_NAME, actionVisible, assignLanes, boolSortValue, bucketRecords, buildMonthGrid, buildUpdatedRecord, coerceInlineValue, compareSortValues, compareYmd, dateOf, dateSortValue, daySlice, defangForPrompt, deriveAll, draftToRecord, emptyRow, enumColorClasses, enumSortValue, enumValueIndex, errorMessage, evaluateDerived, executePresentCollection, fieldVisible, firstMissingRequiredField, isSortableField, itemIdOf, itemLabelOf, labelFieldFor, monthAnchorDate, nextSortDirection, numericSortValue, parseIsoDate, parseIsoDateTime, parseTimeRange, recordSpan, resolveEnumColor, resolveRowRefs, rowFromItem, shortHexId, sortItems, spanCoversDay, stringSortValue, whenMatches, ymdKey };
|
|
130
46
|
|
|
131
47
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/core/presentCollection.ts","../src/core/sortItems.ts"],"sourcesContent":["// presentCollection tool — definition + pure server-side executor.\n//\n// Isomorphic (no Vue, no Node): bundled to the browser as the plugin's\n// `execute`, and run server-side via the host's plugin dispatch route. The\n// executor only validates + echoes the addressing; the live schema + items\n// are fetched client-side by the View through the host's /api/collections\n// routes, so a bad slug surfaces as the View's \"not found\" state.\n\nimport type { ToolContext, ToolDefinition, ToolResult } from \"gui-chat-protocol\";\n\nexport const TOOL_NAME = \"presentCollection\";\n\n/** Render payload carried in the tool result's `data` field; the View mounts\n * off these. Same shape as the tool args. */\nexport interface PresentCollectionData {\n /** Slug of the collection to display (e.g. \"clients\", \"invoices\"). */\n collectionSlug: string;\n /** Optional primary-key value of a single item to open on mount. */\n itemId?: string;\n}\n\nexport type PresentCollectionArgs = PresentCollectionData;\n\nexport const TOOL_DEFINITION: ToolDefinition = {\n type: \"function\",\n name: TOOL_NAME,\n description:\n \"Display a schema-driven collection inline in the chat as an interactive, editable card. Shows the collection's list of records. Pass `itemId` to open one specific record on mount.\",\n parameters: {\n type: \"object\",\n properties: {\n collectionSlug: {\n type: \"string\",\n description: \"The slug of the collection to display (e.g. 'clients', 'invoices', 'contacts').\",\n },\n itemId: {\n type: \"string\",\n description: \"Optional primary-key value of a single record to open in detail view on mount. Omit to show the full list.\",\n },\n },\n required: [\"collectionSlug\"],\n },\n prompt: `After making changes to schema-driven collections, use ${TOOL_NAME} to present either the collection or the item`,\n};\n\nexport const executePresentCollection = async (\n _context: ToolContext,\n args: PresentCollectionArgs,\n): Promise<ToolResult<PresentCollectionData, PresentCollectionData>> => {\n const collectionSlug = typeof args?.collectionSlug === \"string\" ? args.collectionSlug.trim() : \"\";\n if (!collectionSlug) {\n return {\n message: \"presentCollection error: collectionSlug is required\",\n instructions: \"Tell the user you couldn't display the collection because no collection was specified, and ask which collection they mean.\",\n };\n }\n const itemId = typeof args.itemId === \"string\" && args.itemId.trim().length > 0 ? args.itemId.trim() : undefined;\n const data: PresentCollectionData = itemId ? { collectionSlug, itemId } : { collectionSlug };\n const target = itemId ? `${collectionSlug} / ${itemId}` : collectionSlug;\n return {\n message: `Presented collection ${target}`,\n // `data` is the view's source (also the host's render-eligibility signal);\n // `jsonData` is what the LLM sees. Same payload, two audiences.\n data,\n jsonData: data,\n instructions:\n \"The collection has been presented to the user as an interactive card. They can browse, open, edit, create, and delete records directly. No further action is needed unless they ask.\",\n };\n};\n","// Sorting for the collection list table. The header sort toggle (next to\n// each field title) cycles a single active column through none → asc →\n// desc → none; this module turns that state plus a per-field value\n// extractor into an ordered copy of the rows.\n//\n// Two invariants the comparator guarantees:\n// 1. Rows with an empty/missing value for the sorted field always sink\n// to the bottom, regardless of direction.\n// 2. Ties (and the empty group) keep their original order — the sort is\n// stable via the captured source index.\n//\n// Field-type → comparable mapping (see `isSortableField`):\n// string/text/email → string · number/money → numeric ·\n// date/datetime → epoch-ms · enum → declared-index · boolean/toggle →\n// false<true · ref → display label · derived → its display type.\n// markdown/table/image/file/embed get no sort button.\n\nimport type { CollectionItem, CollectionFieldSpec, CollectionFieldType } from \"./schema\";\n\nexport type SortDirection = \"asc\" | \"desc\";\n\nexport interface SortState {\n /** Field key of the single active sort column. */\n field: string;\n direction: SortDirection;\n}\n\n/** A row's comparable value for the active field. Exactly one of `num` /\n * `str` is set when not empty; `empty` rows always sort last. */\nexport interface SortValue {\n empty: boolean;\n num?: number;\n str?: string;\n}\n\nconst EMPTY: SortValue = { empty: true };\n\n/** Field types that render no value text in the table, so offer no sort. */\nconst NON_SORTABLE: ReadonlySet<CollectionFieldType> = new Set<CollectionFieldType>([\"markdown\", \"table\", \"image\", \"file\", \"embed\"]);\n\nexport function isSortableField(field: CollectionFieldSpec): boolean {\n return !NON_SORTABLE.has(field.type);\n}\n\n/** Cycle one column's state: none → asc → desc → none. */\nexport function nextSortDirection(current: SortDirection | null): SortDirection | null {\n if (current === null) return \"asc\";\n if (current === \"asc\") return \"desc\";\n return null;\n}\n\n// ── SortValue constructors (one per comparable kind) ────────────────\n\nexport function numericSortValue(raw: unknown): SortValue {\n if (raw == null || raw === \"\") return EMPTY;\n const num = typeof raw === \"number\" ? raw : Number(raw);\n return Number.isFinite(num) ? { empty: false, num } : EMPTY;\n}\n\nexport function stringSortValue(raw: unknown): SortValue {\n if (raw == null) return EMPTY;\n const str = String(raw);\n return str.trim() === \"\" ? EMPTY : { empty: false, str };\n}\n\nexport function dateSortValue(raw: unknown): SortValue {\n if (raw == null || raw === \"\") return EMPTY;\n const epoch = Date.parse(String(raw));\n // Unparseable dates fall back to a lexical compare rather than vanishing.\n return Number.isNaN(epoch) ? stringSortValue(raw) : { empty: false, num: epoch };\n}\n\n/** Enum sorts by the value's index in the declared `values` list. A value\n * outside the list (or unset) is treated as empty → last. */\nexport function enumSortValue(values: readonly string[] | undefined, raw: unknown): SortValue {\n if (raw == null || raw === \"\") return EMPTY;\n const idx = values ? values.indexOf(String(raw)) : -1;\n return idx < 0 ? EMPTY : { empty: false, num: idx };\n}\n\n/** Boolean / toggle: false < true, never empty (unset reads as false). */\nexport function boolSortValue(checked: boolean): SortValue {\n return { empty: false, num: checked ? 1 : 0 };\n}\n\n// ── Comparator + driver ─────────────────────────────────────────────\n\nexport function compareSortValues(left: SortValue, right: SortValue): number {\n if (left.num !== undefined && right.num !== undefined) return left.num - right.num;\n const leftStr = left.str ?? String(left.num ?? \"\");\n const rightStr = right.str ?? String(right.num ?? \"\");\n return leftStr.localeCompare(rightStr);\n}\n\n/** Stable sort of `items` by `valueOf`. Empties always last; ties hold\n * source order. Returns a new array (does not mutate `items`). */\nexport function sortItems(items: readonly CollectionItem[], direction: SortDirection, valueOf: (item: CollectionItem) => SortValue): CollectionItem[] {\n const dir = direction === \"asc\" ? 1 : -1;\n return items\n .map((item, index) => ({ item, index, sv: valueOf(item) }))\n .sort((left, right) => {\n if (left.sv.empty || right.sv.empty) {\n if (left.sv.empty && right.sv.empty) return left.index - right.index;\n return left.sv.empty ? 1 : -1;\n }\n const base = compareSortValues(left.sv, right.sv);\n return base !== 0 ? base * dir : left.index - right.index;\n })\n .map((decorated) => decorated.item);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/core/presentCollection.ts"],"sourcesContent":["// presentCollection tool — definition + pure server-side executor.\n//\n// Isomorphic (no Vue, no Node): bundled to the browser as the plugin's\n// `execute`, and run server-side via the host's plugin dispatch route. The\n// executor only validates + echoes the addressing; the live schema + items\n// are fetched client-side by the View through the host's /api/collections\n// routes, so a bad slug surfaces as the View's \"not found\" state.\n\nimport type { ToolContext, ToolDefinition, ToolResult } from \"gui-chat-protocol\";\n\nexport const TOOL_NAME = \"presentCollection\";\n\n/** Render payload carried in the tool result's `data` field; the View mounts\n * off these. Same shape as the tool args. */\nexport interface PresentCollectionData {\n /** Slug of the collection to display (e.g. \"clients\", \"invoices\"). */\n collectionSlug: string;\n /** Optional primary-key value of a single item to open on mount. */\n itemId?: string;\n}\n\nexport type PresentCollectionArgs = PresentCollectionData;\n\nexport const TOOL_DEFINITION: ToolDefinition = {\n type: \"function\",\n name: TOOL_NAME,\n description:\n \"Display a schema-driven collection inline in the chat as an interactive, editable card. Shows the collection's list of records. Pass `itemId` to open one specific record on mount.\",\n parameters: {\n type: \"object\",\n properties: {\n collectionSlug: {\n type: \"string\",\n description: \"The slug of the collection to display (e.g. 'clients', 'invoices', 'contacts').\",\n },\n itemId: {\n type: \"string\",\n description: \"Optional primary-key value of a single record to open in detail view on mount. Omit to show the full list.\",\n },\n },\n required: [\"collectionSlug\"],\n },\n prompt: `After making changes to schema-driven collections, use ${TOOL_NAME} to present either the collection or the item`,\n};\n\nexport const executePresentCollection = async (\n _context: ToolContext,\n args: PresentCollectionArgs,\n): Promise<ToolResult<PresentCollectionData, PresentCollectionData>> => {\n const collectionSlug = typeof args?.collectionSlug === \"string\" ? args.collectionSlug.trim() : \"\";\n if (!collectionSlug) {\n return {\n message: \"presentCollection error: collectionSlug is required\",\n instructions: \"Tell the user you couldn't display the collection because no collection was specified, and ask which collection they mean.\",\n };\n }\n const itemId = typeof args.itemId === \"string\" && args.itemId.trim().length > 0 ? args.itemId.trim() : undefined;\n const data: PresentCollectionData = itemId ? { collectionSlug, itemId } : { collectionSlug };\n const target = itemId ? `${collectionSlug} / ${itemId}` : collectionSlug;\n return {\n message: `Presented collection ${target}`,\n // `data` is the view's source (also the host's render-eligibility signal);\n // `jsonData` is what the LLM sees. Same payload, two audiences.\n data,\n jsonData: data,\n instructions:\n \"The collection has been presented to the user as an interactive card. They can browse, open, edit, create, and delete records directly. No further action is needed unless they ask.\",\n };\n};\n"],"mappings":";;;;AAUA,IAAa,YAAY;AAazB,IAAa,kBAAkC;CAC7C,MAAM;CACN,MAAM;CACN,aACE;CACF,YAAY;EACV,MAAM;EACN,YAAY;GACV,gBAAgB;IACd,MAAM;IACN,aAAa;GACf;GACA,QAAQ;IACN,MAAM;IACN,aAAa;GACf;EACF;EACA,UAAU,CAAC,gBAAgB;CAC7B;CACA,QAAQ,0DAA0D,UAAU;AAC9E;AAEA,IAAa,2BAA2B,OACtC,UACA,SACsE;CACtE,MAAM,iBAAiB,OAAO,MAAM,mBAAmB,WAAW,KAAK,eAAe,KAAK,IAAI;CAC/F,IAAI,CAAC,gBACH,OAAO;EACL,SAAS;EACT,cAAc;CAChB;CAEF,MAAM,SAAS,OAAO,KAAK,WAAW,YAAY,KAAK,OAAO,KAAK,EAAE,SAAS,IAAI,KAAK,OAAO,KAAK,IAAI,KAAA;CACvG,MAAM,OAA8B,SAAS;EAAE;EAAgB;CAAO,IAAI,EAAE,eAAe;CAE3F,OAAO;EACL,SAAS,wBAFI,SAAS,GAAG,eAAe,KAAK,WAAW;EAKxD;EACA,UAAU;EACV,cACE;CACJ;AACF"}
|